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

24

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]+"

Il en [\w]va de même pour les expressions régulières Perl, je suppose. Est-ce exact?

Alors, parlons 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 fait 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?

bers
la source

Réponses:

11

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 sedet grepimplé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é à cet égard au cours des dernières décennies).

Dans POSIX BRE et ERE, vous avez la [:alnum:]classe de caractères. Cela correspond aux lettres et aux chiffres de votre environnement local (notez que cela inclut souvent beaucoup plus que a-zA-Z0-9si l'environnement local n'est pas C).

Alors:

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

correspond à un ou plusieurs alnums ou _.

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

Le comportement pour \wseul n'est pas spécifié par POSIX, donc les implémentations sont autorisées à faire ce qu'elles veulent. GNU a grepajouté cela il y a longtemps.

GNU grepavait son propre moteur d'expression régulière, mais il utilise maintenant celui de la bibliothèque GNU (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 existe également un \wopé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 façon dont GNU grep -Putilise PCRE, il a le même problème que sans -P. Cela peut être résolu là-bas en utilisant (*UCP)(bien que cela ait également des effets secondaires dans les environnements locaux non UTF8).

GNU sedutilise également les expressions régulières de la bibliothèque GNU pour ses propres expressions régulières. Il l'utilise de telle manière qu'il n'a pas le même bug que GNU grep.

GNU sedne 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-les perl.

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

Stéphane Chazelas
la source
[_[:alnum:]]est une belle solution de contournement qui me permet de l'étendre comme [\w/]( [_[:alnum:]/]dans ce cas).
bers
1
Cette réponse est désormais dépassée en ce qui concerne les limites de GNU grep.
Stéphane Chazelas
7

Vous avez raison - \wfait 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 sedpeuvent le prendre en charge, mais je dirais que le moyen le plus simple consiste à simplement utiliser perlen sedmode en spécifiant l' -pindicateur. (Avec le -e). (Plus de détails dans perlrun)

Mais vous n'avez pas besoin de le []contourner 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 perlrepour plus de trucs PCRE.

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

Sobrique
la source
Veuillez noter la différence entre \wet [\w]dans ma question. Je vais le mettre à jour avec les sorties de chaque commande pour indiquer clairement laquelle fonctionne et laquelle ne fonctionne pas. En particulier, sedcomprend \w, mais pas [\w]. Aussi, j'ai besoin [\w]de travailler car je veux utiliser [\w/]par exemple.
bers
Dans ce cas, c'est probablement un problème de citation. Quoi qu'il en soit - perlpeut le faire :).
Sobrique
Merci! La réponse de Stéphane Chazelas est un peu plus proche de ce que j'ai demandé (puisque je n'ai pas installé perl - un utilisateur Windows du * b, je suppose), j'ai donc accepté sa réponse.
bres
C'est ok - mais je recommanderais d'installer Perl sur Windows. C'est l'une des premières choses qui se passe dans la mienne, et je la trouve extrêmement utile.
Sobrique
\wétait dans GNU grep (dans les années 80) avant d'être en perl et dans GNU emacs probablement même avant cela.
Stéphane Chazelas
1

Je soupçonne cela grepet je seddécide différemment quand appliquer le []et quand le développer \w. En perl regex \wsignifie n'importe quel caractère de mot, et []définissez un groupe pour appliquer n'importe lequel des caractères à l'intérieur comme une correspondance. Si vous "développez" l' \wavant, []ce sera une classe de caractères de tous les mots. Si, au lieu de cela, vous avez d' []abord une classe de caractères avec deux caractères \, welle correspondra donc à n'importe quel modèle contenant un ou plusieurs de ces deux caractères.

Il semble donc que sedvoir le []et le traiter comme contenant les caractères exacts à faire correspondre au lieu d'honorer la séquence spéciale au \wfur perlet à mesure grep. Bien sûr, les []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 or.

Eric Renouf
la source
Je serais surpris si tel était le cas. \ est un code d'échappement, et vous l'utiliseriez pour échapper les délimiteurs. En soi, cela signifie qu'il doit avoir une priorité plus élevée que toute autre chose. Je pense qu'il est plus probable qu'il ne soit pas implémenté car \wne fait pas partie de la spécification d'expression régulière
Sobrique
Eh bien, empiriquement, cela semble être le cas en utilisant gnu sed pour moi: cela me echo whe\\ere | sed -r 's/[\w]+/gone/gdonne gonehegoneerel' ` and impression qu'il correspond à chacun des w` et fait la substitution
Eric Renouf
Je peux confirmer ce que voit Eric Renouf. Nous voulons donc échapper à la barre oblique inverse en quelque sorte? :)
bers
Je ne pense pas que ce soit la bonne réponse. Sed ne prend tout simplement pas en charge le mélange des différents types de définitions de classes de caractères, donc la réponse est si vous devez utiliser les deux types de classes de caractères choisir un autre outil, ou si vous choisissez sed utiliser la syntaxe qu'il prend en charge
Eric Renouf