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.