2011-05-14 16 views
16

¿Alguien puede explicar cómo podría usar expresiones regulares en Ruby para devolver solo las coincidencias de una cadena?Encontrar líneas en un archivo de texto que coincida con una expresión regular

Por ejemplo, si el código lee en un archivo .txt con una serie de nombres en ella:

John Smith 
James Jones 
David Brown 
Tom Davidson 
etc etc 

..y la palabra para que coincida está tecleada por ser 'uan', lo haría a continuación, simplemente devuelva 'John Smith', pero ninguno de los otros nombres.

Respuesta

14

Tal vez no soy la comprensión del problema por completo, pero se podría hacer algo como:

File.readlines("path/to/file.txt").select { |line| line =~ /ohn/ } 

para obtener una matriz de todas las líneas que coincidan con sus criterios.

9
query = 'ohn' 
names = File.readlines('names.txt') 
matches = names.select { |name| name[/#{query}/i] } 
#=> ["John Smith"] 

Retire la i al final de la expresión regular si desea que la consulta sea sensible a mayúsculas.

+0

que es perfecto, gracias amable señor! – Jbod

21

Aquí hay algunas maneras diferentes de llegar a su destino.

Aviso primero Estoy usando una forma más idiomática de escribir el código para leer líneas de un archivo. Las bibliotecas IO y File de Ruby hacen que sea muy fácil abrir, leer y cerrar el archivo en un paquete ordenado.

File.each_line('file.txt') do |li| 
    puts li if (li['ohn']) 
end 

Que busca 'ohn' en cualquier lugar de la línea, pero no se molesta con una expresión regular.

File.each_line('file.txt') do |li| 
    puts li if (li[/ohn/]) 
end 

Eso busca la misma cadena, solo usa una expresión regular para llegar allí. Funcionalmente es lo mismo que el primer ejemplo.

File.each_line('file.txt') do |li| 
    puts li if (li[/ohn\b/]) 
end 

Esta es una manera un poco más inteligente de buscar nombres que terminan en 'ohn'. Utiliza expresiones regulares pero también especifica que el patrón tiene que ocurrir al final de una palabra. \b significa "límite de palabra".

Además, al leer archivos, es importante pensar siempre con anticipación si el archivo que se está leyendo podría exceder la RAM disponible para su aplicación. Es fácil leer todo un archivo en la memoria en una sola pasada, luego procesarlo desde la memoria RAM, pero puede paralizar o matar a su aplicación o máquina si excede la RAM física disponible para usted.


Cómo se sabe si el código mostrado por las otras respuestas es, de hecho, la carga de todo el archivo en la memoria RAM o es de alguna manera optimizada por streaming desde la función readlines a la función de selección?

De la documentación IO#readlines:

lee el archivo entero especificado por el nombre como líneas individuales, y devuelve esas líneas en una matriz. Las líneas están separadas por sep.

Una consideración adicional es la asignación de memoria durante una lectura grande y masiva.Incluso si tiene suficiente RAM, puede encontrarse con situaciones en las que un lenguaje se ahoga a medida que lee en los datos, descubre que no ha asignado suficiente memoria a la variable y tiene que pausar a medida que capta más. Ese ciclo se repite hasta que se carga todo el archivo.

Me volví sensible a esto hace muchos años cuando estaba cargando un archivo de datos muy grande en una aplicación Perl en el mini más grande de HP, que manejé. La aplicación se detendría durante un par de segundos periódicamente y no pude entender por qué. Me metí en el depurador y no pude encontrar el problema. Finalmente, al rastrear la ejecución usando declaraciones impresas de la vieja escuela, aislé las pausas de un archivo "sorber". Tenía mucha memoria RAM y mucho poder de procesamiento, pero Perl no estaba asignando suficiente memoria. Cambié a la lectura línea por línea y la aplicación voló a través de su procesamiento. Ruby, como Perl, tiene buena E/S, y puede leer un archivo grande muy rápidamente cuando lee línea por línea. Nunca he encontrado una buena razón para sorber un archivo de texto, excepto cuando es posible tener contenido que deseo difundir en varias líneas, pero eso no es una ocurrencia común.

+1

+1 para tener en cuenta la memoria. ¿Sabes si el código mostrado por las otras respuestas está de hecho cargando todo el archivo en la RAM o de alguna manera se optimiza mediante la transmisión desde la función 'readlines' a la función' select'? –

+0

+1 por no leer todo el archivo en la memoria. –

+1

@JasonM, cualquier respuesta que sugiera el uso de 'readlines' está cargando todo el archivo en la memoria. Es como una matriz, pero está en la memoria. –

1

vieja pregunta, pero Array#grep también se puede utilizar para buscar una lista de cadenas

File.readlines("names.txt").grep /#{query}/i 
Cuestiones relacionadas