Ho cercato un po 'questo ma devo usare i termini sbagliati - fa ruby avere un modo per grep per una stringa/regex e restituire anche le 5 linee circostanti (sopra e sotto)? So che potrei semplicemente chiamare lo "grep -C 5 ..."
o anche scrivere il mio metodo, ma sembra che ci sia qualcosa che ruby e io non sto usando i termini di ricerca giusti.Ruby equivalente a "grep -C 5" per ottenere il contesto delle linee attorno alla partita?
risposta
Si può fare con un'espressione regolare. Ecco la stringa che vogliamo per la ricerca:
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 è "\ n" per me, ma per voi potrebbe essere "\ r \ n". Io bastone in una costante:
EOL = '\n'
Per semplificare l'espressione regolare, definiremo il modello per "contesto" solo una volta:
CONTEXT_LINES = 2
CONTEXT = "((?:.*#{EOL}){#{CONTEXT_LINES}})"
ed eseguiremo una ricerca per tutte le linee contenente la parola "quinto". Si noti che questa espressione regolare deve afferrare l'intera linea, compresa la linea di fine, per farlo funzionare:
regexp = /.*fifth.*#{EOL}/
Infine, fare la ricerca e mostrare i risultati:
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"
Non penso che si possa fornire args a grep; basato su api.
È sempre possibile scrivere un metodo. Qualcosa del genere:
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
Questo potrebbe funzionare anche, ma ho trovato la risposta di Wayne per essere più simile a quello che volevo. – wonderfulthunk
Grazie per la il grep contestuale. Ho pensato che potrei aggiungere che quando la corrispondenza si avvicina alla parte superiore o inferiore e si desidera che tutte le linee che possano ottenere anche senza tutte le linee CONTEXT_LINES disponibili, è possibile modificare la definizione di CONTEXT come segue:
CONTEXT = "((?:.*#{EOL}){0,#{CONTEXT_LINES}})"
Per impostazione predefinita, le partite sono avidi, quindi se una parte o la totalità delle linee CONTEXT_LINES disponibili, questo è quello che ti afferra.
Questo è stato fantastico, grazie! Funziona come un incantesimo - ho dovuto tornare indietro e rileggere che il fine riga deve essere incluso nell'espressione regolare che sto cercando, l'ho perso quando ho inizialmente provato questo. – wonderfulthunk
Questo dovrebbe funzionare: /.*fifth.*[#{EOL}]*/ Vedere http://rubular.com/r/skalXLBXcQ –