web-dev-qa-db-fra.com

comment spécifiez-vous des groupes non capturants dans sed?

est-il possible de spécifier des groupes non capturants dans sed?

si c'est le cas, comment?

30
barlop

La réponse est que, au moment de l’écriture, vous ne pouviez pas le supporter. Sed prend en charge BRE et ERE, mais pas PCRE. 

(Remarque: une réponse indique que BRE est également appelé POSIX sed et que ERE est une extension GNU via sed -r. Il reste que PCRE n'est pas pris en charge par sed.)

Perl fonctionnera sous Windows ou Linux

exemples ici

https://superuser.com/questions/416419/Perl-for-matching-with-regular-expressions-in-terminal

par exemple. cela de cygwin dans windows

$ echo -e 'abcd' | Perl -0777 -pe 's/(a)(?:b)(c)(d)/\1/s'
a

$ echo -e 'abcd' | Perl -0777 -pe 's/(a)(?:b)(c)(d)/\2/s'
c

Il existe un programme, bien que pour Windows, qui puisse rechercher et remplacer en ligne de commande et prend en charge PCRE. Cela s'appelle rxrepl. Ce n'est pas bien sûr, mais il recherche et remplace le support PCRE.

C:\blah\rxrepl>echo abc | rxrepl -s "(a)(b)(c)" -r "\1"
a

C:\blah\rxrepl>echo abc | rxrepl -s "(a)(b)(c)" -r "\3"
c

C:\blah\rxrepl>echo abc | rxrepl -s "(a)(b)(?:c)" -r "\3"
Invalid match group requested.

C:\blah\rxrepl>echo abc | rxrepl -s "(a)(?:b)(c)" -r "\2"
c

C:\blah\rxrepl>

L'auteur (pas moi) a mentionné son programme dans une réponse ici https://superuser.com/questions/339118/regex-replace-from-command-line

Il a une très bonne syntaxe.

Le langage standard à utiliser serait Perl, ou presque tout autre langage de programmation utilisé. 

8
barlop

Les parenthèses peuvent être utilisées pour regrouper des alternatives. Par exemple:

sed 's/a\(bc\|de\)f/X/'

dit de remplacer "abcf" ou "adef" par "X", mais les parenthèses aussi capture. Il n'existe pas de possibilité dans sed de faire un tel regroupement sans également capturer. Si vous avez une expression rationnelle complexe qui effectue à la fois la capture du groupement alternatif et _, vous devrez simplement faire attention en choisissant le groupe de capture correct dans votre remplacement.

Vous pourriez peut-être en dire plus sur ce que vous essayez d'accomplir (quel est votre besoin de groupes sans capture) et pourquoi vous souhaitez éviter les groupes de capture.

Modifier:

Il existe un type de crochets sans capture ((?:pattern)) qui font partie de Expressions régulières compatibles Perl (PCRE). Ils ne sont pas pris en charge dans sed (mais le sont avec grep -P).

27
Dennis Williamson

Je présume que vous parlez de la syntaxe de backrefence, qui est constituée de parenthèses ( ) et non de crochets [ ].

Par défaut, sed interprétera ( ) littéralement et ne tentera pas de créer une référence arrière à partir de ceux-ci. Vous aurez besoin de les échapper pour les rendre spéciales comme dans \( \). C’est seulement lorsque vous utilisez l’option GNU sed -r que l’échappement est inversé. Avec sed -r, le ( ) non échappé produira des références et le \( \) échappé sera traité comme un littéral. Exemples à suivre:

POSIX sed

$ echo "foo(###)bar" | sed 's/foo(.*)bar/@@@@/'
@@@@

$ echo "foo(###)bar" | sed 's/foo(.*)bar/\1/'
sed: -e expression #1, char 16: invalid reference \1 on `s' command's RHS
-bash: echo: write error: Broken pipe

$ echo "foo(###)bar" | sed 's/foo\(.*\)bar/\1/'
(###)

GNU sed -r

$ echo "foo(###)bar" | sed -r 's/foo(.*)bar/@@@@/'
@@@@

$ echo "foo(###)bar" | sed -r 's/foo(.*)bar/\1/'
(###)

$ echo "foo(###)bar" | sed -r 's/foo\(.*\)bar/\1/'
sed: -e expression #1, char 18: invalid reference \1 on `s' command's RHS
-bash: echo: write error: Broken pipe

Mettre à jour

D'après les commentaires: 

Des parenthèses ne capturant que des groupes ( ) afin que vous puissiez utiliser quelque chose comme les intervalles {n,m} sans créer de référence arrière \1 n'existent pas. Premièrement, les intervalles ne font pas partie de POSIX sed, vous devez utiliser l'extension GNU -r pour les activer. Dès que vous activez -r, toutes les parenthèses de regroupement seront également capturées pour une utilisation en arrière-plan. Exemples:

$ echo "123.456.789" | sed -r 's/([0-9]{3}\.){2}/###/'
###789

$ echo "123.456.789" | sed -r 's/([0-9]{3}\.){2}/###\1/'
###456.789
3
SiegeX

Comme il a été dit, il n’est pas possible d’avoir des groupes sans capture dans Sed. Cela pourrait être évident, mais les groupes sans capture ne sont pas une nécessité. On peut simplement utiliser ceux qui sont capturés et ignorer ceux qui ne le sont pas, comme s’ils n’étaient pas capturés. Pour référence, les groupes de capture imbriqués sont numérotés par l'ordre de position de "(".

Par exemple., 

echo "Apple and bananas and monkeys" | sed -r "s/((Apple|banana)s?)/\1x/g"

applex et banane s x et singes (remarque: "s" dans les bananes, premier groupe plus important)

contre

echo "Apple and bananas and monkeys" | sed -r "s/((Apple|banana)s?)/\2x/g"

applex et bananax et les singes (note: pas de "s" dans les bananes, deuxième groupe plus petit)

0
Hector Llorens