i gruppi di acquisizione sed non funzionano


27

Ho una stringa del formato [0-9]+\.[0-9]+\.[0-9]. Devo estrarre il primo, il secondo e il terzo numero separatamente. A quanto ho capito, i gruppi di acquisizione dovrebbero essere in grado di farlo. Dovrei essere in grado di usare sed "s/\([0-9]*\)/\1/gper ottenere il primo numero, sed "s/\([0-9]*\)/\2/gper ottenere il secondo numero e sed "s/\([0-9]*\)/\3/gper ottenere il terzo numero. In ogni caso, però, sto ottenendo l'intera stringa. Perché sta succedendo?


6
I gruppi di acquisizione catturano l'intero gruppo ... non i singoli elementi del gruppo. Hai bisogno di qualcosa come 's/\([0-9]\)\([0-9]\)\([0-9]\).*/\1\2\3/'catturare singoli numeri.
Munir,

Risposte:


45

Non possiamo darti una risposta completa senza un esempio del tuo contributo, ma posso dirti che la tua comprensione dei gruppi di acquisizione è sbagliata. Non li usi in sequenza, si riferiscono solo alla regex sul lato sinistro dello stesso operatore di sostituzione. Se catturi, per esempio, /(foo)(bar)(baz)/allora foosarà \1, barsarà \2e bazsarà \3. Non puoi farlo s/(foo)/\1/; s/(bar)/\2/, perché, nella seconda s///chiamata, esiste un solo gruppo acquisito, quindi \2non verrà definito.

Quindi, per acquisire i tuoi tre gruppi di cifre, devi fare:

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

O, più leggibile:

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

1
Qual è il vantaggio di sfuggire alle parentesi nel primo esempio?
Josh M.,

2
@JoshM. è necessario sfuggirli per poter essere utilizzati per acquisire modelli. Normalmente /(foo)/in sed corrisponderà a un (personaggio letterale , seguito da fooe poi da un letterale ). Se si desidera acquisire un gruppo, è necessario uscire dalle parentesi o utilizzare l' -Eopzione.
terdon

Uso quasi sempre la -rbandiera, quindi presumo sia per questo che non mi sono ancora imbattuto in questo.
Josh M.,

1
@JoshM. sì, anche la -rbandiera lo farà, ma non è portatile. GNU sed lo supporta, ma molti altri no. Il -Eè più universale.
terdon

9

Esempio:

$ 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

Oppure, tutti insieme:

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

2

Usa Sed con -r, --regexp-extended per evitare tutte le parentesi sfuggite.

echo "1234.567.89" | sed -r 's/([0-9]+)\.([0-9]+)\.([0-9]+)/\1, \2, \3/' 
1234, 567, 89    #output
Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.