Come estrarre il testo da una stringa usando sed?


95

La mia stringa di esempio è la seguente:

This is 02G05 a test string 20-Jul-2012

Ora dalla stringa sopra voglio estrarre 02G05. Per questo ho provato la seguente regex con sed

$ echo "This is 02G05 a test string 20-Jul-2012" | sed -n '/\d+G\d+/p'

Ma il comando precedente non stampa nulla e il motivo per cui credo è che non è in grado di abbinare nulla al pattern che ho fornito a sed.

Quindi, la mia domanda è cosa sto facendo di sbagliato qui e come correggerlo.

Quando provo la stringa e il pattern sopra con Python ottengo il mio risultato

>>> re.findall(r'\d+G\d+',st)
['02G05']
>>>

6
Python non lo è assolutamente sed. I loro sapori regex sono abbastanza diversi.
— Tripleee

Risposte:


91

Il modello \dpotrebbe non essere supportato dal tuo sed. Prova [0-9]o [[:digit:]]invece.

Per stampare solo la corrispondenza effettiva (non l'intera riga di corrispondenza), utilizzare una sostituzione.

sed -n 's/.*\([0-9][0-9]*G[0-9][0-9]*\).*/\1/p'

6
Grazie ha funzionato bene. Ma ho una domanda sul perché .*è necessario con la tua regex perché quando provo sed -n 's/\([0-9]\+G[0-9]\+\)/\1/p'stampa solo l'intera riga.
— RanRag

7
Ecco perché, non è vero? Sostituisci tutto ciò che viene prima e dopo la partita con norhing, quindi stampa l'intera riga.
— tripleee

1
@ tripleee Questo stampa solo 2G05non 02G05. L'espressione che funziona è's/.*\([0-9][0-9]G[0-9][0-9]*\).*/\1/p'
— Kshitiz Sharma

1
Questo lo codifica a esattamente due cifre. Qualcosa di simile sed -n 's/\(.*[^0-9]\)\?\([0-9][0-9]*G[0-9][0-9]*\).*/\2/p'sarebbe più generale. (Presumo che i tuoi sedsupporti \?per zero o una occorrenza.)
— tripleee

Vedi anche stackoverflow.com/a/48898886/874188 per come sostituire vari altri comuni Perl sfugge come \w, \se così via
— tripleee

99

Che ne dici di usare grep -E?

echo "This is 02G05 a test string 20-Jul-2012" | grep -Eo '[0-9]+G[0-9]+'

3
+1 Questo è più semplice e gestirà correttamente anche il caso di più corrispondenze sulla stessa riga. Un sedcopione complesso potrebbe essere ideato per quel caso, ma perché preoccuparsi?
— tripleee

egrepusa regexp esteso sede grepusa regexp standard, egrepo grep -eo sed -Eusa regexp esteso, e il codice python nella domanda usa PCRE, (espressione regolare comune perl) GNU grep può usare PCRE con l' -Popzione.
— Felipe Buccioni

@FelipeBuccioni in realtà dovrebbe essere egrepo grep -Eosed -r
— SensorSmith

Per una singola (prima) corrispondenza, aggiungi `| head -1` (senza backtick), come da questa risposta a un'altra domanda.
— SensorSmith

1
grepdeve -m 1fermarsi dopo la prima partita.
— tripleee


5

Prova questo invece:

echo "This is 02G05 a test string 20-Jul-2012" | sed 's/.* \([0-9]\+G[0-9]\+\) .*/\1/'

Ma nota, se ci sono due pattern su una riga, verrà stampato il secondo.


O più in generale l'ultimo se ci sono più corrispondenze.
— tripleee

0

Prova a usare rextract . Ti permetterà di estrarre il testo usando un'espressione regolare e riformattarlo.

Esempio:

$ echo "This is 02G05 a test string 20-Jul-2012" | ./rextract '([\d]+G[\d]+)' '${1}'

2G05

Se questo utilizza regex standard, le parentesi quadre intorno \dsono completamente superflue.
— tripleee
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.