Bagaimana cara menggunakan [\ w] + dalam ekspresi reguler di sed?

24

Saya menggunakan Windows, tapi saya kira pertanyaan saya masih ditempatkan dengan benar di sini.

C:\Users\User>grep --version
GNU grep 2.6.3

C:\Users\User>sed --version
GNU sed version 4.2.1

Saya perhatikan bahwa karya-karya berikut (keluaran here):

echo here | grep -E "\w+"
echo here | grep -E "[her]+"

Tapi, ini tidak berhasil (tidak menghasilkan apa-apa):

echo here | grep -E "[\w]+"

Ini lagi tidak (keluaran here):

echo here | grep -P "[\w]+"

Jadi [\w]adalah sesuatu yang spesifik untuk ekspresi reguler Perl, saya kira. Apakah itu benar?

Jadi, mari kita bicara sed. Ini berfungsi (keluaran gone):

echo here | sed -r "s/\w+/gone/"
echo here | sed -r "s/[her]+/gone/"

Dan lagi, ini tidak (keluaran here):

echo here | sed -r "s/[\w]+/gone/"

Sekarang, bagaimana saya bisa mengaktifkan ekspresi reguler Perl untuk sed - apakah ada cara?

bers
sumber

Jawaban:

11

Alat dan versi yang berbeda mendukung variasi ekspresi reguler yang berbeda. Dokumentasi masing-masing akan memberi tahu Anda apa yang mereka dukung.

Ada standar sehingga seseorang dapat mengandalkan serangkaian fitur minimum yang tersedia di semua aplikasi yang sesuai.

Sebagai contoh, semua implementasi modern seddan grepimplementasi ekspresi reguler dasar seperti yang ditentukan oleh POSIX (setidaknya satu versi atau yang lain dari standar, tetapi standar itu belum banyak berkembang dalam hal itu dalam beberapa dekade terakhir).

Di POSIX BRE dan ERE, Anda memiliki [:alnum:]kelas karakter. Yang cocok dengan huruf dan angka di lokal Anda (catatan yang sering mencakup lebih banyak daripada a-zA-Z0-9kecuali lokal adalah C).

Begitu:

grep -x '[[:alnum:]_]\{1,\}'

cocok dengan satu atau lebih alnum atau _.

[\w]diperlukan oleh POSIX untuk mencocokkan backslash atau w. Jadi Anda tidak akan menemukan grepatau sedimplementasi di mana itu tersedia (kecuali melalui opsi non-standar).

Perilaku untuk \wsendiri tidak ditentukan oleh POSIX, jadi implementasi diperbolehkan untuk melakukan apa yang mereka inginkan. GNU grepmenambahkan itu sejak lama.

GNU grepdigunakan untuk memiliki mesin regexp sendiri namun sekarang menggunakan GNU libc's (meskipun ia menanamkan salinannya sendiri).

Ini dimaksudkan untuk mencocokkan alnums dan garis bawah di lokal Anda. Namun, saat ini memiliki bug karena hanya cocok dengan karakter byte tunggal (misalnya, tidak é di lokal UTF-8 meskipun itu jelas huruf dan meskipun itu cocok dengan é di semua lokal tempat é adalah satu karakter).

Ada juga \woperator regexp di perl regexp dan di PCRE. PCRE / perl bukan ekspresi reguler POSIX, mereka hanya hal lain sama sekali.

Sekarang, dengan cara GNU grep -Pmenggunakan PCRE, ia memiliki masalah yang sama seperti tanpa -P. Itu dapat dikerjakan di sana dengan menggunakan (*UCP)(meskipun itu juga memiliki efek samping di lokal non-UTF8).

GNU sedjuga menggunakan regex libc GNU untuk regexpsnya sendiri. Ia menggunakannya sedemikian rupa sehingga tidak memiliki bug yang sama dengan GNU grep.

GNU sedtidak mendukung PCRE. Ada beberapa bukti dalam kode yang telah dicoba sebelumnya, tetapi tampaknya tidak ada dalam agenda lagi.

Jika Anda ingin ekspresi reguler Perl, gunakan saja perl.

Kalau tidak, saya akan mengatakan bahwa daripada mencoba mengandalkan fitur non-standar palsu dari implementasi khusus Anda sed/ grep, akan lebih baik untuk tetap dengan standar dan penggunaan [_[:alnum:]].

Stéphane Chazelas
sumber
[_[:alnum:]]adalah solusi yang bagus yang memungkinkan saya untuk memperpanjang seperti [\w/]( [_[:alnum:]/]dalam hal ini).
bers
1
Jawaban ini sekarang sudah usang sehubungan dengan keterbatasan GNU grep.
Stéphane Chazelas
7

Anda benar - \wadalah bagian dari PCRE - ekspresi reguler yang kompatibel dengan perl. Ini bukan bagian dari regex 'standar'. http://www.regular-expressions.info/posix.html

Beberapa versi sedmungkin mendukungnya, tapi saya sarankan cara termudah adalah dengan menggunakan perldalam sedmode dengan menentukan -pbendera. (Seiring dengan -e). (Lebih detail dalam perlrun)

Tapi Anda tidak perlu mengikutinya []dalam contoh itu - itu untuk kelompok barang yang valid.

echo here  | perl -pe 's/\w+/gone/'

Atau di Windows:

C:\>echo here  | perl -pe "s/\w+/gone/"
gone
C:\>echo here  | perl -pe "s/[\w\/]+/gone/"
gone

Lihat perlrelebih banyak barang PCRE.

Anda bisa mendapatkan perl di sini: http://www.activestate.com/activeperl/downloads

Sobrique
sumber
Harap perhatikan perbedaan antara \wdan [\w]dalam pertanyaan saya. Saya akan memperbaruinya dengan output dari setiap perintah untuk memperjelas mana yang berfungsi dan mana yang tidak. Secara khusus, sedmengerti \w, tetapi tidak [\w]. Juga, saya perlu [\w]bekerja karena saya ingin menggunakan [\w/]misalnya.
bers
Dalam hal ini, itu mungkin masalah mengutip. Either way - perlbisa melakukannya :).
Sobrique
Terima kasih! Jawaban Stéphane Chazelas 'sedikit lebih dekat dengan apa yang saya minta (karena saya tidak memiliki perl diinstal - a du * b pengguna Windows, saya kira), jadi saya menerima jawabannya.
bers
Tidak apa-apa - tapi saya sarankan menginstal Perl di Windows. Ini adalah salah satu hal pertama yang terjadi pada saya, dan saya merasa sangat membantu.
Sobrique
\wberada di GNU grep (tahun 80-an) sebelum berada di perl dan di GNU emacs bahkan mungkin sebelum itu.
Stéphane Chazelas
1

Saya menduga itu grepdan sedmemutuskan secara berbeda kapan harus menerapkan []dan kapan harus memperluas \w. Dalam perl regex \wberarti karakter kata apa pun, dan []tentukan grup untuk menerapkan salah satu karakter di dalamnya sebagai pasangan. Jika Anda "perluas" \wsebelumnya, []itu akan menjadi kelas karakter dari semua karakter kata. Jika, sebaliknya Anda lakukan []pertama Anda akan memiliki kelas karakter dengan dua karakter \dan wsehingga akan ditemukan pola yang mengandung satu atau lebih dari dua karakter.

Jadi sepertinya sedmelihat []dan memperlakukannya sebagai berisi karakter yang tepat untuk mencocokkan bukannya menghormati urutan khusus \wseperti perldan greplakukan. Tentu saja, []ini benar-benar tidak perlu dalam contoh ini, tetapi orang mungkin bisa membayangkan kasus-kasus di mana itu akan menjadi penting, tetapi kemudian Anda bisa membuatnya bekerja dengan orangtua dan ors.

Eric Renouf
sumber
Saya akan terkejut jika begitu. \ adalah kode pelarian, dan Anda akan menggunakannya untuk menghindari pembatas. Secara inheren itu berarti ia harus memiliki prioritas lebih tinggi daripada hal lain. Saya pikir itu lebih mungkin bahwa itu tidak dilaksanakan karena \wbukan bagian dari spec ekspresi reguler
Sobrique
Nah, secara empiris tampaknya menjadi kasus menggunakan gnu sed untuk saya: echo whe\\ere | sed -r 's/[\w]+/gone/gmemberi saya gonehegoneereseolah-olah itu cocok dengan masing-masing ` and w` dan melakukan substitusi
Eric Renouf
Saya dapat mengkonfirmasi apa yang dilihat Eric Renouf. Jadi kita ingin menghapus backslash entah bagaimana? :)
bers
Saya kira itu bukan jawaban yang tepat. Sed hanya tidak mendukung pencampuran berbagai jenis definisi kelas karakter, jadi jawabannya adalah jika Anda harus menggunakan kedua jenis kelas karakter memilih alat lain, atau jika Anda memilih dan menggunakan sintaks yang didukungnya
Eric Renouf