groupes de capture sed ne fonctionnent pas

27

J'ai une chaîne du format [0-9]+\.[0-9]+\.[0-9]. J'ai besoin d'extraire les premier, deuxième et troisième nombres séparément. Si je comprends bien, les groupes de capture devraient être capables de cela. Je devrais pouvoir utiliser sed "s/\([0-9]*\)/\1/gpour obtenir le premier numéro, sed "s/\([0-9]*\)/\2/gpour obtenir le deuxième numéro et sed "s/\([0-9]*\)/\3/gpour obtenir le troisième numéro. Dans chaque cas, cependant, j'obtiens la chaîne entière. Pourquoi cela arrive-t-il?

Melab
la source
6
Les groupes de capture capturent le groupe entier ... pas les éléments individuels du groupe. Vous avez besoin de quelque chose comme 's/\([0-9]\)\([0-9]\)\([0-9]\).*/\1\2\3/'pour capturer des numéros individuels.
Munir

Réponses:

45

Nous ne pouvons pas vous donner une réponse complète sans un exemple de votre contribution, mais je peux vous dire que votre compréhension des groupes de capture est erronée. Vous ne les utilisez pas séquentiellement, ils se réfèrent uniquement à l'expression régulière sur le côté gauche du même opérateur de substitution. Si vous capturez, par exemple, /(foo)(bar)(baz)/alors foosera \1, barsera \2et bazsera \3. Vous ne pouvez pas faire s/(foo)/\1/; s/(bar)/\2/, car, dans le deuxième s///appel, il n'y a qu'un seul groupe capturé, donc \2ne sera pas défini.

Donc, pour capturer vos trois groupes de chiffres, vous devez faire:

sed 's/\([0-9]*\)\.\([0-9]*\)\.\([0-9]*\)/\1 : \2 : \3/'

Ou, le plus lisible:

sed -E 's/([0-9]*)\.([0-9]*)\.([0-9]*)/\1 : \2 : \3/'
terdon
la source
1
Quel est l'avantage d'échapper aux parenthèses dans le premier exemple?
Josh M.
2
@JoshM. vous devez les échapper afin qu'ils puissent être utilisés pour capturer des motifs. Normalement, /(foo)/dans sed correspondra à un (caractère littéral , suivi de foopuis d'un littéral ). Si vous souhaitez capturer un groupe, vous devez soit échapper les parenthèses, soit utiliser l' -Eoption.
terdon
J'utilise presque toujours le -rdrapeau, donc je suppose que c'est pourquoi je ne l'ai pas encore rencontré.
Josh M.
1
@JoshM. oui, le -rdrapeau fera aussi cela, mais il n'est pas portable. GNU sed le supporte mais beaucoup d'autres non. Le -Eest plus universel.
terdon
9

Exemple:

$ echo "123.456.78" |sed 's/\([0-9]*\)\.\([0-9]*\)\.\([0-9]*\)/\1/'
123

$ echo "123.456.78" |sed 's/\([0-9]*\)\.\([0-9]*\)\.\([0-9]*\)/\2/'
456

$ echo "123.456.78" |sed 's/\([0-9]*\)\.\([0-9]*\)\.\([0-9]*\)/\3/'
78

Ou, tous ensemble:

$ echo "123.456.78" |sed 's/\([0-9]*\)\.\([0-9]*\)\.\([0-9]*\)/\1 : \2 : \3/'
123 : 456 : 78
jai_s
la source
2

Utilisez Sed avec -r, --regexp-extended pour éviter toutes les parenthèses échappées.

echo "1234.567.89" | sed -r 's/([0-9]+)\.([0-9]+)\.([0-9]+)/\1, \2, \3/' 
1234, 567, 89    #output
Surya
la source