Bagaimana cara mengekstrak teks dari string menggunakan sed?

98

Contoh string saya adalah sebagai berikut:

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

Sekarang dari string di atas saya ingin mengekstrak 02G05. Untuk itu saya mencoba regex berikut dengan sed

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

Tetapi perintah di atas tidak mencetak apa pun dan alasan saya yakin adalah tidak dapat mencocokkan apa pun dengan pola yang saya berikan ke sed.

Jadi, pertanyaan saya adalah apa yang saya lakukan salah di sini dan bagaimana memperbaikinya.

Ketika saya mencoba string dan pola di atas dengan python, saya mendapatkan hasil saya

>>> re.findall(r'\d+G\d+',st)
['02G05']
>>>
RanRag
sumber
6
Python jelas tidak sed. Rasa regex mereka sangat berbeda.
tripleee

Jawaban:

95

Polanya \dmungkin tidak didukung oleh Anda sed. Coba [0-9]atau [[:digit:]]sebagai gantinya.

Untuk hanya mencetak pertandingan yang sebenarnya (bukan seluruh baris yang cocok), gunakan substitusi.

sed -n 's/.*\([0-9][0-9]*G[0-9][0-9]*\).*/\1/p'
tripleee
sumber
6
Terima kasih itu bekerja dengan baik. Tapi saya punya pertanyaan mengapa .*perlu dengan regex Anda karena ketika saya mencobanya sed -n 's/\([0-9]\+G[0-9]\+\)/\1/p'hanya mencetak seluruh baris.
RanRag
7
Itu sebabnya, bukan? Ganti apa pun yang muncul sebelum dan sesudah pertandingan dengan norhing, lalu cetak seluruh baris.
tripleee
1
@tripleee Ini hanya mencetak 2G05tidak 02G05. Ekspresi yang berhasil adalah's/.*\([0-9][0-9]G[0-9][0-9]*\).*/\1/p'
Kshitiz Sharma
1
Itu mengkodekannya menjadi tepat dua digit. Sesuatu seperti sed -n 's/\(.*[^0-9]\)\?\([0-9][0-9]*G[0-9][0-9]*\).*/\2/p'itu lebih umum. (Saya berasumsi seddukungan Anda \?untuk nol atau satu kejadian.)
tripleee
Lihat juga stackoverflow.com/a/48898886/874188 untuk bagaimana cara mengganti berbagai umum lainnya Perl lolos seperti \w, \s, dll
tripleee
102

Bagaimana kalau menggunakan grep -E?

echo "This is 02G05 a test string 20-Jul-2012" | grep -Eo '[0-9]+G[0-9]+'
mVChr
sumber
3
+1 Ini lebih sederhana, dan juga akan menangani kasus beberapa kecocokan dengan benar pada baris yang sama. sedSkrip yang rumit dapat dibuat untuk kasus itu, tetapi mengapa repot-repot?
tripleee
egrepmenggunakan regexp diperpanjang, seddan grepmenggunakan regexp standar, egrepatau grep -eatau sed -Emenggunakan regexp diperpanjang, dan kode python dalam pertanyaan menggunakan PCRE, (perl ekspresi reguler umum) GNU grep dapat menggunakan PCRE dengan -Popsi.
Felipe Buccioni
@FelipeBuccioni sebenarnya yang seharusnya egrepatau grep -Eataused -r
SensorSmith
Untuk satu pertandingan (pertama), tambahkan `| head -1` (tanpa backticks), sesuai jawaban untuk pertanyaan lain ini.
SensorSmith
1
grepharus -m 1berhenti setelah pertandingan pertama.
tripleee
5

sedtidak mengenali \d, gunakan [[:digit:]]saja. Anda juga harus keluar dari +atau menggunakan -rsakelar ( -Edi OS X).

Perhatikan bahwa ini juga [0-9]berfungsi untuk angka Arab-Hindu.

Dijeda sampai pemberitahuan lebih lanjut.
sumber
Saya sudah mencoba sed -n '/[0-9]\+G[0-9]\+/p'. Sekarang hanya mencetak seluruh string
RanRag
@ Noob: Anda perlu menggunakan substitusi untuk mengecualikan bagian yang tidak ingin Anda cetak .
Dijeda sampai pemberitahuan lebih lanjut.
5

Coba ini sebagai gantinya:

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

Tapi perhatikan, jika ada dua pola dalam satu baris, itu akan mencetak yang ke-2.

Zsolt Botykai
sumber
Atau lebih umum yang terakhir jika ada beberapa kecocokan.
tripleee
0

Coba gunakan rextract . Ini akan memungkinkan Anda mengekstrak teks menggunakan ekspresi reguler dan memformatnya ulang.

Contoh:

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

2G05
Tim Savannah
sumber
Jika ini menggunakan regex standar, tanda kurung siku di sekelilingnya \dbenar-benar berlebihan.
tripleee