Saya mencoba menulis regex yang akan menampilkan semua kata yang panjangnya 10 karakter, dan tidak ada huruf yang berulang.
Sejauh ini, saya punya
grep --colour -Eow '(\w{10})'
Yang merupakan bagian pertama dari pertanyaan. Bagaimana cara saya memeriksa "keunikan"? Saya benar-benar tidak memiliki petunjuk, selain dari itu saya perlu menggunakan referensi kembali.
grep
regular-expression
Dylan Meeus
sumber
sumber
Jawaban:
tidak termasuk kata yang memiliki dua karakter identik.
mengecualikan yang memiliki karakter berulang.
POSIXly:
tr
menempatkan kata-kata pada baris mereka sendiri dengan mengonversi setiap spersamaan karakter non-kata ( cpelengkap alfa-numerik dan garis bawah) ke karakter baris baru.Atau dengan satu
grep
:(kecualikan garis kurang dari 10 dan lebih dari 10 karakter dan yang memiliki karakter muncul setidaknya dua kali).
Hanya dengan satu
grep
(GNU grep dengan dukungan PCRE ataupcregrep
):Yaitu, batas kata (
\b
) diikuti oleh urutan 10 karakter kata (asalkan masing-masing tidak diikuti oleh urutan karakter kata dan diri mereka sendiri, menggunakan operator PCRE pandangan ke depan negatif(?!...)
).Kami beruntung bekerja di sini, karena tidak banyak mesin regexp bekerja dengan referensi balik di dalam bagian berulang.
Perhatikan bahwa (setidaknya dengan versi GNU grep saya)
Tidak berhasil, tapi
tidak (as
echo aa | grep -Pw '(.)\2'
) yang terdengar seperti bug.Anda mungkin ingin:
jika Anda ingin
\w
atau\b
mempertimbangkan huruf apa pun sebagai komponen kata dan bukan hanya huruf ASCII di lokal non-ASCII.Alternatif lain:
Itu adalah batas kata (yang tidak diikuti oleh urutan karakter kata yang berulang) diikuti oleh 10 karakter kata.
Hal-hal yang mungkin ada di benak seseorang:
Babylonish
misalnya akan dicocokkan, karena semua karakter berbeda walaupun ada duaB
s, satu huruf kecil dan satu huruf besar (gunakan-i
untuk mengubah itu).-w
,\w
dan\b
, kata adalah huruf (yang ASCII hanya untuk GNUgrep
untuk saat ini ,[:alpha:]
kelas karakter di lokal Anda jika menggunakan-P
dan(*UCP)
), angka desimal atau garis bawah .c'est
(dua kata berdasarkan definisi kata dalam bahasa Prancis) atauit's
(satu kata berdasarkan definisi kata dalam bahasa Inggris) atau (satu kata sesuai definisirendez-vous
kata dalam bahasa Prancis) tidak dianggap sebagai satu kata.(*UCP)
, Unicode menggabungkan karakter tidak dianggap sebagai komponen kata, jaditéléphone
($'t\u00e9le\u0301phone'
) dianggap sebagai 10 karakter, salah satunya non-alpha.défavorisé
($'d\u00e9favorise\u0301'
) akan dicocokkan meskipun punya duaé
karena itu semua 10 karakter alfa yang berbeda diikuti oleh aksen akut kombinasi (non-alfa, jadi ada batas kata antarae
dan aksennya).sumber
\w
tidak cocok-
.Oke ... inilah cara kikuk untuk string lima karakter:
Karena Anda tidak dapat menempatkan referensi kembali di kelas karakter (misalnya
[^\1|\2]
), Anda harus menggunakan pandangan ke depan negatif -(?!foo)
. Ini adalah fitur PCRE sehingga Anda perlu-P
beralih.Pola untuk string 10 karakter akan jauh lebih lama, tentu saja, tetapi ada metode yang lebih pendek menggunakan pencocokan panjang variabel apa pun ('. *') Di lookahead:
Setelah membaca jawaban Stephane Chazelas yang mencerahkan, saya menyadari ada pola sederhana yang serupa untuk digunakan melalui
-v
sakelar grep :Karena cek menghasilkan satu karakter pada satu waktu, ini akan melihat apakah ada karakter yang diberikan diikuti oleh nol atau lebih karakter (
.*
) dan kemudian kecocokan untuk referensi belakang.-v
membalikkan, hanya mencetak hal-hal yang tidak cocok dengan pola ini. Ini membuat referensi belakang lebih berguna karena mereka tidak dapat dinegasikan dengan kelas karakter, dan secara signifikan:akan bekerja untuk mengidentifikasi string dengan panjang apa pun dengan karakter unik sedangkan:
tidak akan, karena itu akan cocok dengan akhiran apa pun dengan karakter unik (mis.
abcabc
cocok karenaabc
di akhir, danaaaa
karenaa
di akhir - maka string apa pun ). Ini adalah komplikasi yang disebabkan oleh lookaround menjadi nol-lebar (mereka tidak mengkonsumsi apa pun).sumber
(.)(?!.*\1)(.)(?!.*\2)(.)(?!.*\3)(.)(?!\4).
Jika Anda tidak perlu melakukan semuanya dalam regex, saya akan melakukannya dengan dua langkah: pertama-tama cocokkan semua kata 10 huruf, kemudian filter untuk keunikan. Cara terpendek yang saya tahu bagaimana melakukan ini adalah di Perl:
Perhatikan
\W
jangkar tambahan untuk memastikan bahwa hanya kata-kata yang panjangnya tepat 10 karakter yang cocok.sumber
Yang lain menyarankan ini tidak mungkin tanpa berbagai ekstensi untuk sistem ekspresi reguler tertentu yang sebenarnya tidak teratur. Namun, karena bahasa yang ingin Anda cocokkan terbatas, itu jelas teratur. Untuk 3 huruf dari alfabet 4 huruf, akan mudah:
Jelas ini tidak terkendali dengan terburu-buru dengan lebih banyak huruf dan huruf yang lebih besar. :-)
sumber
Opsi
--perl-regexp
(pendek-P
) dari GNUgrep
menggunakan ekspresi reguler yang lebih kuat yang mencakup pola melihat ke depan. Pola berikut mencari setiap huruf yang tidak muncul di sisa kata:Namun perilaku run-time sangat buruk, karena
\w*
dapat memiliki panjang yang hampir tak terbatas. Dapat dibatasi\w{,8}
, tetapi itu juga memeriksa di luar batas kata 10 huruf. Karena itu, pola berikut pertama memeriksa panjang kata yang benar:Sebagai file uji saya telah menggunakan file besar ≈ 500 MB:
Memperbarui:
Saya tidak dapat menemukan perubahan signifikan dalam perilaku run-time untuk operator yang tidak serakah (
\w*?
) atau operator yang posesif ((...){10}+
). Agak sedikit lebih cepat tampaknya penggantian opsi-w
:Pembaruan grep dari versi 2.13 ke 2.18 jauh lebih efektif. File tes hanya butuh ≈ 6 s.
sumber
\w{,8}?
) membantu untuk beberapa jenis input (meskipun tidak terlalu signifikan). Penggunaan yang bagus\g{-1}
untuk mengatasi bug grep GNU.\g{-1}
, karena itu membuat pola lebih mandiri di lokasi. Dalam bentuk ini dapat digunakan sebagai bagian dari pola yang lebih besar.Solusi Perl:
tetapi tidak berhasil
atau
diuji dengan perl v5.14.2 dan v5.18.2
sumber