วิธีจับคู่ แต่ไม่จับภาพเป็นส่วนหนึ่งของ regex หรือไม่


209

ฉันมีรายการสตริง 123-...456บางคนก็มีของแบบฟอร์ม ส่วนตัวแปร "... " อาจเป็น:

  • สตริง "apple" ตามด้วยยัติภังค์เช่น 123-apple-456
  • สตริง "Banana" ตามด้วยยัติภังค์เช่น 123-banana-456
  • สตริงว่างเช่น123-456(โปรดสังเกตว่ามีเครื่องหมายขีดคั่นอยู่หนึ่งอัน)

คำอื่นที่ไม่ใช่ "apple" หรือ "Banana" นั้นไม่ถูกต้อง

สำหรับทั้งสามกรณีนี้ฉันต้องการจับคู่ "apple", "Banana" และ "" ตามลำดับ โปรดทราบว่าฉันไม่ต้องการจับภาพยัติภังค์ แต่ฉันต้องการจับคู่เสมอ หากสตริงนั้นไม่ใช่แบบฟอร์ม123-...456ตามที่อธิบายไว้ข้างต้นแสดงว่าไม่มีการจับคู่เลย

ฉันจะเขียนนิพจน์ทั่วไปเพื่อทำสิ่งนี้ได้อย่างไร สมมติว่าฉันมีรสชาติที่อนุญาตให้กลุ่ม lookahead, lookbehind, lookaround และกลุ่มที่ไม่ถูกจับ


ข้อสังเกตสำคัญที่นี่คือเมื่อคุณมี "แอปเปิล" หรือ "กล้วย" คุณต้องมียัติภังค์ต่อท้าย แต่คุณไม่ต้องการจับคู่ และเมื่อคุณจับคู่สตริงว่างคุณต้องไม่มีเครื่องหมายขีดคั่นต่อท้าย ฉันคิดว่า regex ที่ห่อหุ้มคำยืนยันนี้จะเป็นสิ่งที่ถูกต้อง


คุณต้องการจับคู่ทุกอย่างยกเว้นยัติภังค์หรือไม่
BrunoLM

คำตอบ:


285

วิธีเดียวที่จะไม่ใช้บางสิ่งบางอย่างคือการใช้การยืนยันแบบมองไปรอบ ๆ :

(?<=123-)((apple|banana)(?=-456)|(?=456))

เพราะถึงแม้จะมีกลุ่มที่ไม่ได้ถูกจับ(?:…)การแสดงออกปกติทั้งการจับเนื้อหาที่ตรงกันของพวกเขา แต่นี้แสดงออกปกติตรงเท่านั้นappleหรือbananaถ้ามันนำหน้าด้วย123-และตามด้วย-456หรือมันตรงกับสตริงที่ว่างเปล่าถ้ามันนำหน้าด้วยและตามมาด้วย123-456

|Lookaround  |    Name      |        What it Does                       |
-----------------------------------------------------------------------
|(?=foo)     |   Lookahead  | Asserts that what immediately FOLLOWS the |
|            |              |  current position in the string is foo    |
-------------------------------------------------------------------------
|(?<=foo)    |   Lookbehind | Asserts that what immediately PRECEDES the|
|            |              |  current position in the string is foo    |
-------------------------------------------------------------------------
|(?!foo)     |   Negative   | Asserts that what immediately FOLLOWS the |
|            |   Lookahead  |  current position in the string is NOT foo|
-------------------------------------------------------------------------
|(?<!foo)    |   Negative   | Asserts that what immediately PRECEDES the|
|            |   Lookbehind |  current position in the string is NOT foo|
-------------------------------------------------------------------------

1
+1 - ในกรณีนี้คุณสามารถแก้ไขได้โดยใช้กลุ่ม 1 มากกว่ากลุ่ม 0 แต่นี่คือความแตกต่างที่ยอดเยี่ยม (และบอบบาง!)
Ben Blank

@Ben Blank: แน่นอนขึ้นอยู่กับการตีความ "จับคู่" และ "จับ"
Gumbo

8
ไม่ได้รับการสนับสนุนใน JavaScript, yay ! จะดีถ้ามีวิธีการที่เป็นมิตรกับ JS แต่ก็ไม่เลวเลย +0.5 (การปัดเศษ; D)
GiantCowFilms

รักการยืนยันรอบดู! ใช้งานได้ดีกับทับทิมเช่นกัน
Rots

โซลูชั่นที่สมบูรณ์แบบฉันรักสิ่งนี้
Tr Qun Quang สวัสดี

15

อัปเดต: ต้องขอบคุณGermánRodríguez Herrera!

ใน javascript ลอง: /123-(apple(?=-)|banana(?=-)|(?!-))-?456/

จำไว้ว่าผลลัพธ์อยู่ในกลุ่มที่ 1

Debuggex Demo


8

ลอง:

123-(?:(apple|banana|)-|)456

ที่จะตรงกับapple, bananaหรือสตริงว่างเปล่าและต่อไปนี้มันจะมี 0 หรือ 1 ยัติภังค์ ฉันผิดที่ไม่ต้องการกลุ่มจับภาพ ฉันโง่


สิ่งนี้ไม่ถูกต้องเนื่องจากตรงกับตัวอย่างเช่น "123-coconut-456"
David Stone

คิดว่าคุณต้องการทั่วไปมากกว่า ... แก้ไข
โทมัส

5

ฉันได้แก้ไขหนึ่งในคำตอบ (โดย @ op1ekun):

123-(apple(?=-)|banana(?=-)|(?!-))-?456

เหตุผลก็คือคำตอบจาก @ op1ekun ตรงกัน"123-apple456"เช่นกันโดยไม่ต้องใส่เครื่องหมายยัติภังค์หลังจากแอปเปิ้ล


3

ลองสิ่งนี้:

/\d{3}-(?:(apple|banana)-)?\d{3}/

1
สิ่งนี้ไม่ถูกต้องเนื่องจากตรงเช่น "123-coconut-456"
David Stone

@david: มันแตกต่างจากตัวอย่าง "Banana" ของคุณอย่างไร
SilentGhost

@SilentGhost: ผมเพียงต้องการที่จะจับappleหรือbananaหรือ "" ค่าอื่น ๆ ทั้งหมดไม่ถูกต้องตามที่ระบุไว้
David Stone

sry ในกรณีนั้น: / \ d {3} - (? :( แอปเปิ้ล | กล้วย) -)? \ d {3} /
slosd

1
ตัวอย่างนี้แสดงให้เห็นว่าเป็นไปได้ที่จะมีกลุ่มที่ไม่ถูกดักจับโดยไม่ใช้ lookahead และ lookbehind
Vince Panuccio

0

รูปแบบของการแสดงออกโดย @Gumbo ที่ใช้ใน\Kการรีเซ็ตตำแหน่งการแข่งขันเพื่อป้องกันการรวมบล็อกหมายเลขในการแข่งขัน ใช้งานได้ในรสชาติ PCRE regex

123-\K(?:(?:apple|banana)(?=-456)|456\K)

ตรงกัน:

Match 1  apple
Match 2  banana
Match 3

-3

โดยไกลที่ง่าย (ทำงานสำหรับหลาม) '123-(apple|banana)-?456'เป็น


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