web-dev-qa-db-fra.com

Comment faire un match non-gourmand dans grep?

Je veux grep la correspondance la plus courte et le motif devrait être quelque chose comme:

<car ... model=BMW ...>
...
...
...
</car>

... signifie n'importe quel caractère et l'entrée est multiple.

159
syker

Vous recherchez un match non-gourmand (ou paresseux). Pour obtenir une correspondance non gourmande dans les expressions régulières, vous devez utiliser le modificateur ? après le quantificateur. Par exemple, vous pouvez changer .* à .*?.

Par défaut, grep ne prend pas en charge les modificateurs non gloutons, mais vous pouvez utiliser grep -P pour utiliser la syntaxe Perl.

249
Mark Byers

En réalité le .*? ne fonctionne que dans Perl. Je ne suis pas sûr de ce que serait la syntaxe équivalente des expressions rationnelles étendues grep. Heureusement, vous pouvez utiliser la syntaxe Perl avec grep so grep -P fonctionnerait mais grep -E qui est identique à egrep ne fonctionnerait pas (ce serait gourmand).

Voir aussi: http://blog.vinceliu.com/2008/02/non-greedy-regular-expression-matching.html

80
John Smith

grep

Pour une correspondance non-gourmande dans grep, vous pouvez utiliser une classe de caractères inversée. En d'autres termes, essayez d'éviter les caractères génériques.

Par exemple, pour extraire tous les liens vers les fichiers jpeg depuis le contenu de la page, utilisez:

grep -o '"[^" ]\+.jpg"'

Pour traiter plusieurs lignes, dirigez l’entrée par xargs en premier. Pour des performances optimales, utilisez ripgrep .

10
kenorb

Mon grep qui fonctionne après avoir essayé des choses dans ce fil de discussion:

echo "hi how are you " | grep -shoP ".*? "

Assurez-vous simplement d'ajouter un espace à chacune de vos lignes

(Le mien était une recherche ligne par ligne pour cracher des mots)

9
jonz

La réponse courte utilise l'expression régulière suivante:

(?s)<car .*? model=BMW .*?>.*?</car>
  • (? s) - cela fait une correspondance sur plusieurs lignes
  • . *? - correspond à n'importe quel caractère, un nombre de fois paresseux (correspondance minimale)

Une réponse (un peu) plus compliquée est:

(?s)<([a-z\-_0-9]+?) .*? model=BMW .*?>.*?</\1>

Cela permettra de faire correspondre car1 et car2 dans le texte suivant

<car1 ... model=BMW ...>
...
...
...
</car1>
<car2 ... model=BMW ...>
...
...
...
</car2>
  • (..) représente un groupe de capture
  • \ 1 dans ce contexte correspond au texte sametext avec la dernière correspondance en capturant le groupe 1
0
jmc