Ekspresi Reguler: Apakah ada operator DAN?

708

Jelas, Anda dapat menggunakan |(pipa?) Untuk mewakili OR, tetapi apakah ada cara untuk mewakili ANDjuga?

Secara khusus, saya ingin mencocokkan paragraf teks yang berisi SEMUA frase tertentu, tetapi tanpa urutan tertentu.

Hugoware
sumber
1
Apakah maksud Anda ingin menemukan frasa dalam teks, di mana setiap frasa tersebut merupakan permutasi yang sah dari kata-kata dalam frasa yang diberikan?
Nietzche-jou
2
Saya meletakkan ini di sini karena tiga atau empat jawaban mengabaikannya. Lookahead tidak cocok dengan panjang yang sama untuk setiap klausa, kecuali jika diakhiri dengan $. Satu lookahead bisa cocok dengan empat karakter, dan 6. lainnya. Misalnya, (? = A *) (? = Aab) akan cocok dengan aabaaaaba
Zachary Vance
2
coba gunakan karakter "space" untuk operator "AND".
1 I'd like to match paragraphs of text.. 2. Berisi teks tidak sesuai pesanan . Nomor 1 terbuka untuk interpretasi. Nomor 2 dapat dilakukan dengan beberapa cara. Cara 1 (?:(?:(?(1)(?!))\b(phrase1)\b.*?|(?(2)(?!))\b(phrase2)\b.*?)){2}:, Cara 2: (?=.*\bphrase1\b)(?=.*\bphrase2\b)di mana dalam hal ini, pencocokan paragraf dalam kasus ini tidak ditentukan hingga definisi paragraf diformalkan.

Jawaban:

385

Gunakan ekspresi reguler yang tidak dikonsumsi.

Notasi khas (yaitu Perl / Java) adalah:

(?=expr)

Ini berarti " expr pertandingan tetapi setelah itu terus mencocokkan pada titik pertandingan asli."

Anda dapat melakukan sebanyak ini dari yang Anda inginkan, dan ini akan menjadi "dan." Contoh:

(?=match this expression)(?=match this too)(?=oh, and this)

Anda bahkan dapat menambahkan grup tangkap di dalam ekspresi non-konsumsi jika Anda perlu menyimpan beberapa data di dalamnya.

Jason Cohen
sumber
3
perl -e "q {some stuff and things} = ~ / (? = some) (? = stuff) (? = things) /? cetak 'ya': cetak 'tidak'" cetak 'tidak'.
Robert P
27
Harus disebutkan bahwa contoh khusus ini disebut pernyataan lookahead positif. Ini memiliki kegunaan lain selain "dan". Perhatikan bahwa teks tidak dikonsumsi.
strager
7
Menggunakan (? =) Seperti ini menghasilkan regex yang tidak pernah berhasil. Tapi itu adalah analog konjungsi ke |. OP salah dalam apa yang menurutnya akan menyelesaikan masalahnya.
Nietzche-jou
10
perl -e "q {some stuff and things} = ~ /(?=.*some)(?=.*stuff)(?=.*things)/? print 'yes': print 'no'"
kriss
3
Bisakah Anda menambahkan beberapa contoh mudah dalam kode perl dalam jawaban Anda?
Pithikos
343

Anda perlu menggunakan lookahead seperti yang dikatakan beberapa responden lain, tetapi lookahead harus memperhitungkan karakter lain antara kata target dan posisi pertandingan saat ini. Sebagai contoh:

(?=.*word1)(?=.*word2)(?=.*word3)

The .*di lookahead pertama memungkinkannya cocok dengan banyak karakter yang diperlukan sebelum sampai ke "word1". Kemudian posisi pertandingan diatur ulang dan lookahead kedua mencari "word2". Atur ulang lagi, dan bagian terakhir cocok dengan "word3"; karena ini adalah kata terakhir yang Anda periksa, tidak perlu dilihat, tetapi tidak sakit.

Untuk mencocokkan seluruh paragraf, Anda harus melabuhkan regex di kedua ujungnya dan menambahkan final .*untuk menggunakan karakter yang tersisa. Menggunakan notasi gaya Perl, itu akan menjadi:

/^(?=.*word1)(?=.*word2)(?=.*word3).*$/m

Pengubah 'm' adalah untuk mode multline; itu memungkinkan ^dan $cocok di batas paragraf ("batas garis" di regex-spoke). Sangat penting dalam hal ini bahwa Anda tidak menggunakan pengubah 's', yang memungkinkan metacharacter titik mencocokkan baris baru serta semua karakter lainnya.

Terakhir, Anda ingin memastikan Anda mencocokkan seluruh kata dan bukan hanya fragmen kata yang lebih panjang, jadi Anda perlu menambahkan batas kata:

/^(?=.*\bword1\b)(?=.*\bword2\b)(?=.*\bword3\b).*$/m
Alan Moore
sumber
8
Tepat sekali - ada tutorial tentang ini juga! ocpsoft.org/tutorials/regular-expressions/and-in-regex
Lincoln
9
Terima kasih banyak. * Ini membuat perbedaan
Gennadiy Ryabkin
1
+1 untuk jawaban yang jelas dan berhasil menampilkan salah satu kegunaan terbaik untuk lookaheads (tidak seperti penggunaan seperti peretasan untuk menghitung persentase kecocokan kata sandi). :)
zx81
1
@Liam :. MySQL menggunakan rasa POSIX ERE, jadi tidak. Ini secara efektif mengorbankan fitur yang mendukung kinerja, yang tampaknya masuk akal bagi saya. Ada informasi lebih lanjut di sini .
Alan Moore
3
ganti .*dengan [\s\S]*dalam javascript jika Anda memiliki baris baru seperti .pada mesin regex javascript tidak cocok dengan baris baru dan tidak dapat dibuat dengan pengubah
Wesley Smith
41

Lihat contoh ini:

Kami memiliki 2 regexps A dan B dan kami ingin mencocokkan keduanya, jadi dalam pseudo-code tampilannya seperti ini:

pattern = "/A AND B/"

Itu dapat ditulis tanpa menggunakan operator DAN seperti ini:

pattern = "/NOT (NOT A OR NOT B)/"

di PCRE:

"/(^(^A|^B))/"

regexp_match(pattern,data)
fanjabi
sumber
24
Itu benar dalam hal logika formal, tetapi sama sekali tidak membantu di sini. Dalam regex, TIDAK bisa lebih sulit untuk diungkapkan daripada DAN.
Alan Moore
@marvin_dpr Ini bekerja untuk saya di CMake sedangkan saran lainnya (?=expr)tidak. Tampaknya tergantung pada implementasi.
Melebius
38
Tidak ^berarti "permulaan string" dalam sintaks regex?
Lambda Fairy
3
Dalam regex secara umum, ^negasi hanya pada awal kelas karakter. Kecuali CMake melakukan sesuatu yang sangat funky (sampai-sampai menyebut bahasa pencocokan pola mereka "regex" dapat dianggap menyesatkan atau salah). Saya menduga fakta bahwa itu berhasil untuk Anda adalah kecelakaan yang terisolasi.
tripleee
29

Anda dapat melakukannya dengan ekspresi reguler tetapi mungkin Anda menginginkan yang lain. Misalnya menggunakan beberapa regexp dan menggabungkannya dalam klausa if.

Anda dapat menghitung semua permutasi yang mungkin dengan regexp standar, seperti ini (cocok dengan a, b dan c dalam urutan apa pun):

(abc)|(bca)|(acb)|(bac)|(cab)|(cba)

Namun, ini membuat regexp yang sangat panjang dan mungkin tidak efisien, jika Anda memiliki lebih dari beberapa istilah.

Jika Anda menggunakan beberapa versi regexp yang diperluas, seperti Perl atau Java, mereka memiliki cara yang lebih baik untuk melakukan ini. Jawaban lain menyarankan menggunakan operasi lookahead positif.

Juha Syrjälä
sumber
10
Saya tidak berpikir pendekatan Anda lebih tidak efisien daripada 3 lookaheads dengan backtracking bencana mereka. Tentu ini lebih panjang untuk ditulis, tetapi perhatikan bahwa Anda dapat dengan mudah membuat polanya secara otomatis. Perhatikan bahwa Anda dapat meningkatkannya agar gagal lebih cepat a(bc|cb)|b(ac|ca)|c(ab|ba). Dan yang paling penting, Anda bisa menggunakannya dengan semua rasa regex.
Casimir et Hippolyte
27

Operator AND tersirat dalam sintaks RegExp.
Operator OR sebaliknya harus ditentukan dengan pipa.
RegExp berikut:

var re = /ab/;

berarti huruf a DAN surat itu b.
Ini juga berfungsi dengan grup:

var re = /(co)(de)/;

itu berarti grup co DAN grup de.
Mengganti (implisit) DAN dengan OR akan membutuhkan baris berikut:

var re = /a|b/;
var re = /(co)|(de)/;
Emanuele Del Grande
sumber
29
Sayangnya, ini bukan yang diminta OP. Ini menemukan apa pun dalam urutan itu, sedangkan mereka menginginkannya dalam urutan apa pun. Lihatlah jawabannya dengan stackoverflow.com/users/20938/alan-moore di bawah ini yang mana yang benar.
JESii
1
@ YESUS terima kasih atas poin Anda, Anda benar dan saya salah paham dengan pertanyaan dari Hugoware, saya berfokus terutama pada kalimat pertamanya. Jawaban yang tepat adalah penggunaan yang tepat dari operator lookahead, seperti yang ditulis AlanMoore. Bagaimanapun saya pikir seseorang mungkin menganggap klarifikasi saya berguna, seperti yang telah dibatalkan, jadi saya tidak akan membuang semuanya. Salam.
Emanuele Del Grande
13

Apakah tidak mungkin dalam kasus Anda untuk melakukan DAN pada beberapa hasil yang cocok? dalam pseudocode

regexp_match(pattern1, data) && regexp_match(pattern2, data) && ...
pengguna54579
sumber
3
Saya berada dalam situasi di mana saya memiliki beberapa kode yang merupakan tabel data aturan, dengan string pencocokan pola regex tunggal untuk menguji validitas aturan. Pindah ke beberapa tes bukan sesuatu yang bisa saya lakukan dalam kasus saya, dan umumnya dalam kasus orang lain juga!
Alan Wolfe
11

Mengapa tidak menggunakan awk?
dengan awk regex AND, ATAU masalahnya sangat sederhana

awk '/WORD1/ && /WORD2/ && /WORD3/' myfile
mug896
sumber
9

Jika Anda menggunakan ekspresi reguler Perl, Anda dapat menggunakan tampilan positif:

Sebagai contoh

(?=[1-9][0-9]{2})[0-9]*[05]\b

akan menjadi angka lebih besar dari 100 dan habis dibagi 5

jpalecek
sumber
8

Anda bisa menyalurkan output Anda ke regex lain. Menggunakan grep, Anda bisa melakukan ini:

grep A | grep B

pengumpul sampah
sumber
8

Selain jawaban yang diterima

Saya akan memberi Anda beberapa contoh praktis yang akan membuat segalanya menjadi lebih jelas bagi sebagian dari Anda. Sebagai contoh katakanlah kita memiliki tiga baris teks:

[12/Oct/2015:00:37:29 +0200] // only this + will get selected
[12/Oct/2015:00:37:x9 +0200]
[12/Oct/2015:00:37:29 +020x]

Lihat demo di sini DEMO

Apa yang ingin kita lakukan di sini adalah memilih tanda + tetapi hanya jika setelah dua angka dengan spasi dan jika sebelum empat angka. Itulah satu-satunya kendala. Kami akan menggunakan ungkapan reguler ini untuk mencapainya:

'~(?<=\d{2} )\+(?=\d{4})~g'

Catatan jika Anda memisahkan ekspresi itu akan memberi Anda hasil yang berbeda.

Atau mungkin Anda ingin memilih beberapa teks di antara tag ... tetapi bukan tag! Maka Anda bisa menggunakan:

'~(?<=<p>).*?(?=<\/p>)~g'

untuk teks ini:

<p>Hello !</p> <p>I wont select tags! Only text with in</p> 

Lihat demo di sini DEMO

DevWL
sumber
Jawaban mana yang merupakan jawaban yang diterima? Silakan tambahkan tautan ke sana untuk masa depan saya.
James Brown
6

Urutan selalu tersirat dalam struktur ekspresi reguler. Untuk mencapai yang Anda inginkan, Anda harus mencocokkan string input beberapa kali dengan ekspresi yang berbeda.

Apa yang ingin Anda lakukan tidak mungkin dengan regexp tunggal.

pilif
sumber
Secara teknis itu tidak mungkin, tetapi tidak layak untuk diterapkan. Saya tidak tahu mengapa seseorang turun jabatan ...
Robert P
13
Mungkin karena itu tidak hanya mungkin, itu sederhana, dengan asumsi rasa regex Anda mendukung lookaheads. Dan itu taruhan yang bagus; sebagian besar bahasa pemrograman utama saat ini mendukungnya.
Alan Moore
3

Gunakan DAN di luar ekspresi reguler. Dalam PHP lookahead operator sepertinya tidak bekerja untuk saya, saya malah menggunakan ini

if( preg_match("/^.{3,}$/",$pass1) && !preg_match("/\s{1}/",$pass1))
    return true;
else
    return false;

Regex di atas akan cocok jika panjang kata sandi adalah 3 karakter atau lebih dan tidak ada spasi dalam kata sandi.

Hammad Khan
sumber