2010-05-03 7 views
6

He buscado esto un poco pero debo estar usando los términos incorrectos - ¿Ruby tiene una forma de grep para una cadena/expresión regular y también devuelve las 5 líneas circundantes (arriba y abajo)? Sé que podría llamar al "grep -C 5 ..." o incluso escribir mi propio método, pero parece que algo de rubí tendría y simplemente no estoy usando los términos de búsqueda correctos.Ruby equivalente a "grep -C 5" para obtener el contexto de las líneas alrededor del partido?

Respuesta

6

Usted puede hacerlo con una expresión regular. Aquí está la cadena que desea buscar:

s = %{The first line 
The second line 
The third line 
The fourth line 
The fifth line 
The sixth line 
The seventh line 
The eight line 
The ninth line 
The tenth line 
} 

EOL es "\ n" para mí, pero para usted puede ser que sea "\ r \ n". Yo me quedo en una constante:

EOL = '\n' 

Para simplificar la expresión regular, vamos a definir el patrón de "contexto" una sola vez:

CONTEXT_LINES = 2 
CONTEXT = "((?:.*#{EOL}){#{CONTEXT_LINES}})" 

Y vamos a buscar cualquier línea que contiene la palabra "quinto". Tenga en cuenta que esta expresión regular debe tomar toda la línea, incluyendo la línea de fin de, para que funcione:

regexp = /.*fifth.*#{EOL}/ 

Por último, hacer la búsqueda y mostrar los resultados:

s =~ /^#{CONTEXT}(#{regexp})#{CONTEXT}/ 
before, match, after = $1, $2, $3 
p before # => "The third line\nThe fourth line\n" 
p match  # => "The fifth line\n" 
p after  # => "The sixth line\nThe seventh line\n" 
+0

Esto fue genial, gracias! Funciona a las mil maravillas. Tuve que volver y volver a leer que el final de línea debe incluirse en la expresión regular que estoy buscando, me lo perdí cuando probé esto inicialmente. – wonderfulthunk

+0

Esto debería funcionar: /.*fifth.*[#{EOL}]*/ Ver http://rubular.com/r/skalXLBXcQ –

0

No creo que pueda suministrar args a grep; basado en el api.

Siempre puede escribir un método. Algo a lo largo de las líneas de esto:

def new_grep(enum, pattern, lines) 
values = enum.grep(/pattern/).map do |x| 
    index = enum.index(x) 
    i = (index - lines < 0) ? 0 : index - lines 
    j = (index + lines >= enum.length) ? enum.length-1 : index + lines 
    enum[i..j] 
end 
return values.flatten.uniq 
end 
+0

Éste podría funcionar también, pero encontré que la respuesta de Wayne era más acorde con lo que yo quería. – wonderfulthunk

2

Gracias por el grep contextual Pensé que podría agregar, que cuando la coincidencia se acerca a la parte superior o inferior y aún desea que todas las líneas puedan igualarse sin todas las líneas CONTEXT_LINES disponibles, puede cambiar la definición de CONTEXTO para que sea como sigue:

CONTEXT = "((?:.*#{EOL}){0,#{CONTEXT_LINES}})" 

Por defecto, las coincidencias son codiciosos, por lo que si parte o la totalidad de las líneas CONTEXT_LINES disponibles, eso es lo que va a agarrar.

Cuestiones relacionadas