web-dev-qa-db-fra.com

Comment utiliser [\ w] + dans l'expression régulière dans sed?

Je suis sous Windows, mais je suppose que ma question est toujours correctement placée ici.

C:\Users\User>grep --version
GNU grep 2.6.3

C:\Users\User>sed --version
GNU sed version 4.2.1

J'ai remarqué que les travaux suivants (sortie here):

echo here | grep -E "\w+"
echo here | grep -E "[her]+"

Mais cela ne fonctionne pas (rien en sortie):

echo here | grep -E "[\w]+"

Cela fait à nouveau (sortie here):

echo here | grep -P "[\w]+"

Donc [\w] est quelque chose de spécifique aux expressions régulières Perl, je suppose. Est-ce exact?

Parlons donc de sed. Cela fonctionne (sortie gone):

echo here | sed -r "s/\w+/gone/"
echo here | sed -r "s/[her]+/gone/"

Et encore une fois, cela ne fonctionne pas (sortie here):

echo here | sed -r "s/[\w]+/gone/"

Maintenant, comment puis-je activer les expressions régulières Perl pour sed - existe-t-il un moyen?

26
bers

Différents outils et versions de ceux-ci prennent en charge différentes variantes d'expressions régulières. La documentation de chacun vous indiquera ce qu'ils prennent en charge.

Il existe des normes permettant de se fier à un ensemble minimal de fonctionnalités disponibles dans toutes les applications conformes.

Par exemple, toutes les implémentations modernes de sed et grep implémentent des expressions régulières de base comme spécifié par POSIX (au moins une version ou l'autre de la norme, mais cette norme n'a pas beaucoup évolué dans ce égard au cours des dernières décennies).

Dans POSIX BRE et ERE, vous avez le [:alnum:] classe de caractères. Cela correspond aux lettres et aux chiffres de votre région (notez que cela inclut souvent beaucoup plus que a-zA-Z0-9 sauf si la locale est C).

Donc:

grep -x '[[:alnum:]_]\{1,\}'

correspond à un ou plusieurs alnums ou _.

[\w] est requis par POSIX pour faire correspondre la barre oblique inverse ou w. Vous ne trouverez donc pas d'implémentation grep ou sed là où elle est disponible (sauf via des options non standard).

Le comportement de \w seul n'est pas spécifié par POSIX, donc les implémentations sont autorisées à faire ce qu'elles veulent. GNU grep l'a ajouté il y a longtemps.

GNU grep avait son propre moteur d'expression régulière, mais il utilise maintenant celui de GNU libc (bien qu'il intègre sa propre copie).

Il est destiné à faire correspondre les alnums et les traits de soulignement dans votre environnement local. Cependant, il a actuellement un bogue en ce qu'il ne correspond qu'à des caractères à un octet (par exemple, pas é dans un environnement local UTF-8 même s'il s'agit clairement d'une lettre et même s'il correspond à é dans tous les environnements locaux où é est un seul personnage).

Il y a aussi un \w opérateur regexp dans Perl regexp et dans PCRE. PCRE/Perl ne sont pas des expressions régulières POSIX, c'est juste une tout autre chose.

Maintenant, avec la manière GNU grep -P utilise PCRE, il a le même problème que sans -P. Cela peut être résolu cependant en utilisant (*UCP) (bien que cela ait également des effets secondaires dans les locales non UTF8).

GNU sed utilise aussi les GNU libc regexs pour ses propres regexps. Il l'utilise de telle manière qu'il n'a pas le même bug que GNU grep.

GNU sed ne prend pas en charge les PCRE. Il y a des preuves dans le code qu'il a déjà été tenté, mais il ne semble plus être à l'ordre du jour.

Si vous voulez les expressions régulières de Perl, utilisez simplement Perl.

Sinon, je dirais que plutôt que d'essayer de s'appuyer sur une fonctionnalité non standard bidon de votre implémentation particulière de sed/grep, il serait préférable de s'en tenir à la norme et d'utiliser [_[:alnum:]].

11

Vous avez raison - \w fait partie des expressions régulières compatibles PCRE - Perl. Cela ne fait cependant pas partie de l'expression rationnelle "standard". http://www.regular-expressions.info/posix.html

Certaines versions de sed peuvent le prendre en charge, mais je suggère que le moyen le plus simple consiste à simplement utiliser Perl en mode sed en spécifiant le -p drapeau. (Avec le -e). (Plus de détails dans perlrun )

Mais vous n'avez pas besoin de [] autour dans cet exemple - c'est pour des groupes de choses valides.

echo here  | Perl -pe 's/\w+/gone/'

Ou sous Windows:

C:\>echo here  | Perl -pe "s/\w+/gone/"
gone
C:\>echo here  | Perl -pe "s/[\w\/]+/gone/"
gone

Voir perlre pour plus d'informations sur PCRE.

Vous pouvez obtenir Perl ici: http://www.activestate.com/activeperl/downloads

7
Sobrique

Je soupçonne que grep et sed décident différemment quand appliquer le [] et quand développer le \w. Dans Perl regex \w signifie n'importe quel caractère Word et [] définir un groupe pour appliquer l'un des caractères à l'intérieur comme une correspondance. Si vous "développez" le \w avant le [] ce sera une classe de caractères de tous les caractères Word. Si, à la place, vous faites [] vous aurez d'abord une classe de caractères avec deux caractères \ et w pour correspondre à tout modèle contenant un ou plusieurs de ces deux caractères.

Il semble donc que sed voit le [] et en le traitant comme contenant les caractères exacts à faire correspondre au lieu d'honorer la séquence spéciale \w comme Perl et grep font. Bien sûr, le [] sont complètement inutiles dans cet exemple, mais on pourrait peut-être imaginer des cas où cela serait important, mais alors vous pourriez le faire fonctionner avec des parenthèses et des ors.

1
Eric Renouf