Ekspresi reguler untuk mencocokkan substring yang tidak diikuti oleh substring tertentu lainnya

115

Saya membutuhkan regex yang akan cocok blahfooblahtetapi tidakblahfoobarblah

Saya ingin itu hanya cocok dengan foo dan segala sesuatu di sekitar foo, selama tidak diikuti oleh bar.

Saya mencoba menggunakan ini: foo.*(?<!bar)yang cukup dekat, tetapi cocok blahfoobarblah. Tampilan negatif di belakang harus cocok dengan apa pun dan bukan hanya bilah.

Bahasa spesifik yang saya gunakan adalah Clojure yang menggunakan regex Java di bawah tenda.

EDIT: Lebih khusus lagi, saya juga membutuhkannya untuk lulus blahfooblahfoobarblahtetapi tidak blahfoobarblahblah.

Rayne
sumber
1
Apakah Anda mencoba menggunakan foo. * (? <! Bar. *)?
Thibault Falise

Jawaban:

158

Mencoba:

/(?!.*bar)(?=.*foo)^(\w+)$/

Tes:

blahfooblah            # pass
blahfooblahbarfail     # fail
somethingfoo           # pass
shouldbarfooshouldfail # fail
barfoofail             # fail

Penjelasan ekspresi reguler

NODE                     EXPLANATION
--------------------------------------------------------------------------------
  (?!                      look ahead to see if there is not:
--------------------------------------------------------------------------------
    .*                       any character except \n (0 or more times
                             (matching the most amount possible))
--------------------------------------------------------------------------------
    bar                      'bar'
--------------------------------------------------------------------------------
  )                        end of look-ahead
--------------------------------------------------------------------------------
  (?=                      look ahead to see if there is:
--------------------------------------------------------------------------------
    .*                       any character except \n (0 or more times
                             (matching the most amount possible))
--------------------------------------------------------------------------------
    foo                      'foo'
--------------------------------------------------------------------------------
  )                        end of look-ahead
--------------------------------------------------------------------------------
  ^                        the beginning of the string
--------------------------------------------------------------------------------
  (                        group and capture to \1:
--------------------------------------------------------------------------------
    \w+                      word characters (a-z, A-Z, 0-9, _) (1 or
                             more times (matching the most amount
                             possible))
--------------------------------------------------------------------------------
  )                        end of \1
--------------------------------------------------------------------------------
  $                        before an optional \n, and the end of the
                           string

Regex lainnya

Jika Anda hanya ingin mengecualikan bartepat setelahnya foo, Anda dapat menggunakan

/(?!.*foobar)(?=.*foo)^(\w+)$/

Sunting

Anda memperbarui pertanyaan Anda untuk membuatnya spesifik.

/(?=.*foo(?!bar))^(\w+)$/

Tes baru

fooshouldbarpass               # pass
butnotfoobarfail               # fail
fooshouldpassevenwithfoobar    # pass
nofuuhere                      # fail

Penjelasan baru

(?=.*foo(?!bar))memastikan a fooditemukan tetapi tidak diikuti secara langsungbar

maček
sumber
Ini sangat dekat, dan jawaban yang sangat bagus. Saya tahu saya tidak akan cukup spesifik. :( Saya membutuhkan ini: "blahfoomeowwoof / foobar /" untuk lulus karena "foo" yang sepi, tetapi bukan blahfoobarmeowwoof ini Jika memungkinkan.
Rayne
Sebagai pertanyaan sampingan, bagaimana cara mencocokkan sesuatu seperti "bot" tetapi tidak dengan "pembotolan"?
Rayne
Iya. Saya dapat menggunakan apa yang saya miliki sekarang, tetapi akan lebih mudah jika saya bisa mencocokkan bot tetapi tidak pembotolan. Aku sangat menyesal. Saya tidak berpengalaman dengan regex, dan saya khawatir saya perlahan-lahan mencari tahu apa yang saya inginkan sendiri. : p
Rayne
1
@Rayne, ini pertanyaan yang sama. Dalam contoh Anda di atas, Anda ingin mencocokkan footetapi tidak foobar. Untuk mencocokkan bottetapi tidak botters, Anda akan menggunakan /(?=.*bot(?!ters))^(\w+)$/.
maček
Yah, saya biasanya membidik seluruh kata. Seperti yang saya katakan, saya bingung tentang apa yang sebenarnya saya inginkan dan apa yang benar-benar mungkin. Melakukannya seperti ini akan berhasil. Terima kasih atas waktunya. :)
Rayne
55

Untuk mencocokkan foopengikut dengan sesuatu yang tidak dimulai dengan bar, coba

foo(?!bar)

Versi Anda dengan tampilan negatif secara efektif adalah "cocokkan foodiikuti dengan sesuatu yang tidak diakhiri bar". The .*pertandingan semua barblah, dan (?<!bar)terlihat kembali di lahdan cek yang tidak cocok bar, yang tidak, sehingga pertandingan pola keseluruhan.

stevemegson
sumber
Jadi saya mencoba ini untuk regex yang dirancang untuk mencocokkan string "apakah Anda" asalkan tidak diikuti dengan "katakan". Ini berfungsi saat membedakan antara "apakah Anda mengatakan" dan "menurut Anda", misalnya, tetapi "apakah Anda" dengan sendirinya tidak tertangkap, dan seharusnya begitu. Ada saran?
soosus
2

Gunakan pandangan negatif ke depan sebagai gantinya:

\s*(?!\w*(bar)\w*)\w*(foo)\w*\s*

Ini berhasil untuk saya, semoga membantu. Semoga berhasil!

Audie
sumber
Regex sederhana namun efektif, yang juga berfungsi untuk mengecualikan string berulang ("foofoo"). Sempurna!
Jonas Byström
1

Anda menulis komentar yang menyarankan Anda seperti ini untuk mencocokkan semua kata dalam sebuah string, bukan seluruh string itu sendiri.

Daripada menumbuk semua ini dalam komentar, saya mempostingnya sebagai jawaban baru.

Regex Baru

/(?=\w*foo(?!bar))(\w+)/

Contoh teks

foowithbar fooevenwithfoobar notfoobar foohere notfoobarhere butfooisokherebar notfoobarhere andnofuu needfoo

Cocok

foowithbar fooevenwithfoobar foohere butfooisokherebar needfoo

maček
sumber
0

Permintaan kecocokan spesifik Anda dapat dicocokkan dengan:

\w+foo(?!bar)\w+

Ini akan cocok blahfooblahfoobarblahtapi tidak blahfoobarblahblah.

Masalah dengan ekspresi reguler Anda foo.*(?<!bar)adalah .*setelahnya foo. Itu cocok dengan banyak karakter apa pun termasuk karakter setelahnya bar.

dawg
sumber