regex เพื่อจับคู่สตริงย่อยที่ไม่ได้ตามด้วยสตริงย่อยอื่น ๆ


116

ฉันต้องการนิพจน์ทั่วไปที่ตรงกันblahfooblahแต่ไม่ใช่blahfoobarblah

ฉันต้องการให้มันจับคู่เฉพาะ foo และทุกอย่างรอบ ๆ foo ตราบเท่าที่ไม่ได้ตามด้วย bar

ฉันพยายามใช้นี้foo.*(?<!bar)ซึ่งเป็นค่อนข้างใกล้เคียง blahfoobarblahแต่มันตรงกับ การมองในแง่ลบที่อยู่เบื้องหลังจะต้องจับคู่กับอะไรก็ได้ไม่ใช่แค่บาร์

ภาษาเฉพาะที่ฉันใช้คือ Clojure ซึ่งใช้ Java regexes ภายใต้ประทุน

แก้ไข: โดยเฉพาะอย่างยิ่งผมยังต้องการที่จะผ่านแต่ไม่blahfooblahfoobarblahblahfoobarblahblah


1
คุณลองใช้ foo. * (? <! bar. *)
Thibault Falise

คำตอบ:


158

ลอง:

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

แบบทดสอบ:

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

คำอธิบายนิพจน์ทั่วไป

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 อื่น ๆ

หากคุณต้องการยกเว้นเฉพาะbarเมื่ออยู่ในภายหลังfooคุณสามารถใช้

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

แก้ไข

คุณได้อัปเดตคำถามของคุณเพื่อให้เฉพาะเจาะจง

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

การทดสอบใหม่

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

คำอธิบายใหม่

(?=.*foo(?!bar))ตรวจสอบให้แน่ใจfooว่าพบ แต่ไม่ได้ติดตามโดยตรงbar


นี่ใกล้มากและเป็นคำตอบที่ดีมาก ฉันรู้ว่าฉันไม่เจาะจงมากพอ :( ฉันต้องการสิ่งนี้: "blahfoomeowwoof / foobar /" ให้ผ่านเพราะ "foo" ที่โดดเดี่ยว แต่ไม่ใช่ blahfoobarmeowwoof นี้ถ้าเป็นไปได้
Rayne

สำหรับคำถามข้างเคียงเราจะจับคู่สิ่งต่างๆเช่น "บอท" แต่ไม่ใช่ "ขวด" ได้อย่างไร
Rayne

ใช่. ฉันสามารถใช้สิ่งที่ฉันมีตอนนี้ได้ แต่มันจะง่ายกว่าถ้าฉันจับคู่บอท แต่ไม่ใช่บอท ฉันเสียใจมาก. ฉันไม่มีประสบการณ์กับ regexes และฉันกลัวว่าฉันจะค่อยๆหาสิ่งที่ต้องการด้วยตัวเอง : p
Rayne

1
@Rayne นี่คือคำถามเดียวกัน ในตัวอย่างข้างต้นของคุณคุณต้องการที่จะตรงแต่ไม่foo foobarเพื่อให้ตรงbotแต่ไม่คุณจะใช้botters /(?=.*bot(?!ters))^(\w+)$/
maček

โดยทั่วไปฉันมุ่งเป้าไปที่ทั้งคำ อย่างที่ฉันพูดฉันสับสนเกี่ยวกับสิ่งที่ฉันต้องการและสิ่งที่เป็นไปได้จริงๆ ทำแบบนี้จะได้ผล ขอบคุณสำหรับเวลา :)
Rayne

55

หากต้องการจับคู่สิ่งfooต่อไปนี้ด้วยสิ่งที่ไม่ได้ขึ้นต้นด้วยbarให้ลอง

foo(?!bar)

เวอร์ชันของคุณที่มีลักษณะเชิงลบคือ "จับคู่fooตามด้วยสิ่งที่ไม่ได้ลงท้ายbar" อย่างมีประสิทธิภาพ .*ตรงทั้งหมดbarblahและ(?<!bar)หันกลับมามองlahและการตรวจสอบว่ามันไม่ตรงกับbarที่มันไม่ได้เพื่อให้ตรงกับรูปแบบทั้ง


ดังนั้นฉันจึงลองสิ่งนี้กับนิพจน์ทั่วไปที่ออกแบบมาให้ตรงกับสตริง "คุณ" ตราบใดที่ไม่ได้ตามด้วย "พูด" ใช้งานได้เมื่อแยกความแตกต่างระหว่าง "คุณเคยพูด" และ "คุณคิดว่า" แต่เพียงแค่ "คุณ" ไม่ได้รับการจับภาพและควร ข้อเสนอแนะใด ๆ ?
soosus

2

ใช้การมองไปข้างหน้าในแง่ลบแทน:

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

สิ่งนี้ได้ผลสำหรับฉันหวังว่ามันจะช่วยได้ โชคดี!


regex ที่เรียบง่าย แต่มีประสิทธิภาพซึ่งใช้ได้กับการยกเว้นสตริงซ้ำ ("foofoo") ที่สมบูรณ์แบบ!
Jonas Byström

1

คุณเขียนความคิดเห็นที่แนะนำว่าคุณชอบสิ่งนี้เพื่อจับคู่คำทั้งหมดในสตริงแทนที่จะเป็นสตริงทั้งหมด

แทนที่จะรวมทั้งหมดนี้ในความคิดเห็นฉันโพสต์เป็นคำตอบใหม่

Regex ใหม่

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

ข้อความตัวอย่าง

foowithbar fooevenwithfoobar notfoobar foohere notfoobarhere butfooisokherebar notfoobarhere andnofuu needsfoo

ไม้ขีด

foowithbar fooevenwithfoobar foohere butfooisokherebar needsfoo


0

คำขอจับคู่เฉพาะของคุณสามารถจับคู่ได้โดย:

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

นี้จะตรงแต่ไม่blahfooblahfoobarblahblahfoobarblahblah

ปัญหากับ regex ของคุณfoo.*(?<!bar)คือหลังจากที่.* fooมันตรงกับเป็นจำนวนมากของตัวละครใด ๆ barรวมทั้งตัวละครหลัง

โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.