Tidak perlu seluruh baris, hanya kecocokan dari ekspresi reguler

15

Saya hanya perlu mendapatkan kecocokan dari ekspresi reguler:

$ cat myfile.txt | SOMETHING_HERE "/(\w).+/"

Keluaran harus hanya apa yang cocok, di dalam tanda kurung.

Jangan pikir saya bisa menggunakan grep karena cocok dengan seluruh baris.

Tolong beri tahu saya cara melakukan ini.

Alex L
sumber

Jawaban:

12

2 hal:

  • Seperti yang dinyatakan oleh @Rory, Anda membutuhkan -oopsi, jadi hanya kecocokan yang dicetak (bukan seluruh baris)
  • Selain itu, Anda perlu -Ppilihan, untuk menggunakan ekspresi reguler Perl, yang mencakup elemen berguna seperti Lihat di depan (?= ) dan Lihat di belakang (?<= ) , yang mencari bagian, tetapi tidak benar-benar cocok dan mencetaknya.

Jika Anda hanya menginginkan bagian di dalam parensis yang cocok:

grep -oP '(?<=\/\()\w(?=\).+\/)' myfile.txt

jika file mengandung sengatan /(a)5667/, grep akan mencetak 'a', karena:

  • /(ditemukan oleh \/\(, tetapi karena mereka berada dalam pandangan-belakang (?<= ) mereka tidak dilaporkan
  • adicocokkan dengan \wdan dengan demikian dicetak (karena -o)
  • )5667/ditemukan b < \).+\/, tetapi karena mereka dalam pandangan ke depan (?= ) mereka tidak dilaporkan
DrYak
sumber
18

Gunakan -oopsi di grep.

Misalnya:

$ echo "foobarbaz" | grep -o 'b[aeiou]r'
bar
Rory
sumber
4
Astaga ... Apakah Anda tahu berapa kali saya bergumul dengan sedreferensi untuk melakukan itu?
Insyte
10
Opsi o untuk grep / egrep hanya mengembalikan apa yang cocok dengan seluruh ekspresi reguler, bukan hanya apa yang ada dalam () seperti yang dia minta.
Kyle Brandt
1
Namun, itu adalah hal yang sangat baik untuk diketahui :-)
Kyle Brandt
2
@KyleBrandt: Untuk mencocokkan hanya satu bagian (misalnya: parenses) dimungkinkan untuk menandai sisanya dengan melihat ke depan atau melihat ke belakang: (? <=) Dan (? =)
DrYak
6
    sed -n "s/^.*\(captureThis\).*$/\1/p"

-n      don't print lines
s       substitute
^.*     matches anything before the captureThis 
\( \)   capture everything between and assign it to \1 
.*$     matches anything after the captureThis 
\1      replace everything with captureThis 
p       print it
Joshua
sumber
4

Jika Anda hanya menginginkan apa yang ada di dalam tanda kurung, Anda memerlukan sesuatu yang mendukung menangkap sub pertandingan (Kelompok Pengambilan Bernama atau Bernomor). Saya tidak berpikir grep atau egrep dapat melakukan ini, perl dan sed bisa. Misalnya, dengan perl:

Jika file yang disebut foo memiliki baris di dalamnya adalah sebagai berikut:

/adsdds      /

Dan kamu juga:

perl -nle 'print $1 if /\/(\w).+\//' foo

Huruf a dikembalikan. Itu mungkin bukan yang Anda inginkan. Jika Anda memberi tahu kami apa yang ingin dicocokkan, Anda mungkin mendapatkan bantuan yang lebih baik. $ 1 adalah apa pun yang ditangkap dalam set kurung pertama. $ 2 akan menjadi set kedua dll.

Kyle Brandt
sumber
Saya hanya mencoba mencocokkan apa yang ada dalam tanda kurung. Sepertinya meneruskannya ke perl atau skrip php mungkin jawabannya.
Alex L
4

Karena Anda menandai pertanyaan Anda sebagai bash selain shell , ada solusi lain selain grep :

Bash memiliki mesin ekspresi regulernya sendiri sejak versi 3.0, menggunakan =~operator, seperti Perl.

sekarang, diberikan kode berikut:

#!/bin/bash
DATA="test <Lane>8</Lane>"

if [[ "$DATA" =~ \<Lane\>([[:digit:]]+)\<\/Lane\> ]]; then
        echo $BASH_REMATCH
        echo ${BASH_REMATCH[1]}
fi
  • Perhatikan bahwa Anda harus menjalankannya sebagai bashdan bukan hanya shuntuk mendapatkan semua ekstensi
  • $BASH_REMATCH akan memberikan seluruh string sesuai dengan seluruh ekspresi reguler, jadi <Lane>8</Lane>
  • ${BASH_REMATCH[1]} akan memberikan bagian yang cocok dengan grup 1, dengan demikian hanya 8
DrYak
sumber
Dear @DrYak, saya harap Anda tidak mem-parsing XML dengan regex di sini .. :)
joonas.fi
Ini bahkan lebih buruk. Saya parsing campuran mengerikan data XML dan FASTA (yang keduanya menggunakan >simbol untuk tujuan yang sama sekali berbeda) sebagaimana dimuntahkan oleh perangkat lunak penyelarasan skala cepat paralel SANSparallel . Tentu saja kedua format tersebut di-interlaced tanpa ada pelarian. Jadi tidak mungkin untuk melemparkan beberapa pustaka XML standar pada ini. Dan saya menggunakan Bash regex pada titik kode ini karena saya hanya perlu mengekstrak beberapa data, dan 2 regex melakukan pekerjaan lebih baik bagi saya daripada menulis pengurai khusus untuk kekacauan ini. #LifeInBioinformatics
DrYak
Dengan kata lain: ada titik di mana mengekstraksi 1 angka tunggal lebih mudah dilakukan dengan regex rathan daripada menari seluruh tango XML
DrYak
Hah, mengerti! :)
joonas.fi
2

Dengan asumsi file tersebut berisi:

$ cat file
Text-here>xyz</more text

Dan Anda ingin karakter antara >dan </, Anda dapat menggunakan:

grep -oP '.*\K(?<=>)\w+(?=<\/)' file
sed -nE 's:^.*>(\w+)</.*$:\1:p' file
awk '{print(gensub("^.*>(\\w+)</.*$","\\1","g"))}' file
perl -nle 'print $1 if />(\w+)<\//' file

Semua akan mencetak string "xyz".

Jika Anda ingin menangkap digit dari baris ini:

$ cat file
Text-<here>1234</text>-ends

grep -oP '.*\K(?<=>)[0-9]+(?=<\/)' file
sed -E 's:^.*>([0-9]+)</.*$:\1:' file
awk '{print(gensub(".*>([0-9]+)</.*","\\1","g"))}' file
perl -nle 'print $1 if />([0-9]+)<\//' file

Panah
sumber
Bagi saya yang penting adalah menyadari bahwa tidak bekerja dengan sed. Ada alasan mengapa Anda menggunakan [0-9] + di sana. :)
user27432
@ user27423 Ini tidak, tapi kelas karakter POSIX ( membaca menyakitkan , membaca menyenangkan ) lakukan: echo 'Text-<here>1234</text>-ends' | sed -E 's|.*>([[:digit:]]+)<.*|\1|'. Dalam beberapa kasus (misalnya [0-9]vs. [[:digit:]]) mereka tidak membantu keterbacaan, dalam kasus lain saya pikir mereka dapat membantu (misalnya [ \t\n\r\f\v]vs. [:space:]).
Samuel Harmer
0

Ini akan memenuhi apa yang Anda minta, tetapi saya tidak berpikir itu yang Anda inginkan. Saya meletakkan .*di depan regex untuk memakan apa pun sebelum pertandingan, tapi itu adalah operasi serakah, jadi ini hanya cocok dengan \wkarakter kedua dari belakang dalam string.

Perhatikan bahwa Anda harus keluar dari parens dan +.

sed 's/.*\(\w\).\+/\1/' myfile.txt
Chad Huneycutt
sumber