Je l'ai cherché un peu mais je dois utiliser les mauvais termes - est-ce que ruby a un moyen de grep pour une chaîne/regex et retourne aussi les 5 lignes environnantes (ci-dessus et ci-dessous)? Je sais que je pourrais juste appeler "grep -C 5 ..."
ou même écrire ma propre méthode, mais il semble que quelque chose aurait ruby et je n'utilise pas les bons termes de recherche.Ruby équivalent à "grep -C 5" pour obtenir le contexte des lignes autour du match?
Répondre
Vous pouvez le faire avec une expression régulière. Voici la chaîne que nous voulons rechercher:
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 est « \ n » pour moi, mais pour vous, il est peut-être « \ r \ n ». Je vais le coller dans une constante:
EOL = '\n'
Pour simplifier l'expression régulière, nous allons définir le modèle pour « contexte » juste une fois:
CONTEXT_LINES = 2
CONTEXT = "((?:.*#{EOL}){#{CONTEXT_LINES}})"
Et nous allons rechercher pour toute ligne contenant le mot "cinquième". Notez que cette expression régulière doit saisir toute la ligne, y compris la fin de ligne, pour que cela fonctionne:
regexp = /.*fifth.*#{EOL}/
Enfin, faire la recherche et afficher les résultats:
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"
Je ne pense pas que vous pouvez fournir des args pour grep; basé sur le api.
Vous pouvez toujours écrire une méthode. Quelque chose dans le sens de ceci:
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
Celui-ci pourrait aussi fonctionner, mais j'ai trouvé la réponse de Wayne plus conforme à ce que je voulais. – wonderfulthunk
Merci pour le grep contextuel. Je pensais que je pourrais ajouter, que lorsque le match se rapproche du haut ou du bas et que vous voulez encore toutes les lignes peuvent obtenir même sans toutes les lignes CONTEXT_LINES disponibles, vous pouvez changer la définition de CONTEXT sera comme suit:
CONTEXT = "((?:.*#{EOL}){0,#{CONTEXT_LINES}})"
Par défaut, les correspondances sont avides, donc si tout ou partie des lignes CONTEXT_LINES disponibles, c'est ce que vous prenez.
C'était super, merci! Cela fonctionne comme un charme - je devais revenir en arrière et relire que la fin de ligne doit être incluse dans l'expression régulière que je cherche, j'ai manqué cela quand j'ai d'abord essayé ceci. – wonderfulthunk
Cela devrait fonctionner: /.*fifth.*[#{EOL}]*/ Voir http://rubular.com/r/skalXLBXcQ –