Regex - วิธีจับคู่ทุกอย่างยกเว้นรูปแบบเฉพาะ


171

ฉันจะเขียน regex เพื่อจับคู่สตริงที่ไม่ตรงกับรูปแบบเฉพาะได้อย่างไร ฉันต้องเผชิญกับสถานการณ์ที่ต้องจับคู่รูปแบบ (A และ ~ B)


PCRE จะดีที่สุดสำหรับนี้: ดูแบบ Regex เพื่อให้ตรงกับเมื่อ ... ไม่รวม / ยกเว้นระหว่าง ฉันลบfindstrแท็กเนื่องจากคำตอบทั้งหมดที่นี่ไม่ถูกต้องสำหรับแท็ก
Wiktor Stribiżew

คำตอบ:


192

คุณสามารถใช้การยืนยันล่วงหน้า:

(?!999)\d{3}

999ตัวอย่างนี้ตรงกับตัวเลขสามหลักอื่นที่ไม่ใช่


แต่ถ้าคุณไม่ได้ใช้นิพจน์ทั่วไปกับคุณสมบัตินี้ (ดูการเปรียบเทียบของ Expression Flavours ) คุณอาจต้องสร้างนิพจน์ทั่วไปด้วยคุณสมบัติพื้นฐานด้วยตัวคุณเอง

นิพจน์ปกติที่เข้ากันได้กับไวยากรณ์พื้นฐานเท่านั้นจะเป็น:

[0-8]\d\d|\d[0-8]\d|\d\d[0-8]

นี้ไม่ตรงกับลำดับตัวเลขใด ๆ 999ที่สามที่ไม่ได้เป็น


1
มองไปข้างหน้าไม่ได้มาตรฐานไวยากรณ์นิพจน์ปกติก็เป็นส่วนขยายของ Perl มันจะทำงานเฉพาะใน Perl, PCRE (RegEx Perl เข้ากันได้) หรือการใช้งานที่ไม่ได้มาตรฐานอื่น ๆ
Juliano

10
อาจไม่เป็นมาตรฐาน แต่ภาษาที่ทันสมัยที่สุดไม่สนับสนุนหรือไม่ วันนี้ภาษาอะไรไม่รองรับการมองหัว
ไบรอัน Oakley

1
นั่นเป็นเรื่องจริง แต่รสชาติของ regex ส่วนใหญ่สนับสนุนคุณสมบัตินี้ (ดู < regular-expressions.info/refflavours.html> )
Gumbo

1
ฉันคิดว่า regex สุดท้ายจะไม่ตรงกับ 009, 019 ... ฯลฯ
เซบาสเตียน Viereck

1
Standard Lex for C ไม่ได้ใช้ PCREs :-(
pieman72

30

หากคุณต้องการจับคู่คำในสตริงและไม่ให้ตรงกับคำ B ตัวอย่างเช่น: หากคุณมีข้อความ:

1. I have a two pets - dog and a cat
2. I have a pet - dog

หากคุณต้องการค้นหาบรรทัดข้อความที่มีสุนัขเป็นสัตว์เลี้ยงและไม่มีแมวคุณสามารถใช้นิพจน์ทั่วไปนี้ได้:

^(?=.*?\bdog\b)((?!cat).)*$

มันจะหาบรรทัดที่สองเท่านั้น:

2. I have a pet - dog

เขาล้มเหลวในการพูดถึงคำถาม แต่ OP จริง ๆ แล้วใช้findstrคำสั่งDOS มันเป็นเพียงส่วนย่อย ๆ ของความสามารถที่คุณคาดว่าจะพบในเครื่องมือ regex lookahead ไม่ได้อยู่ในหมู่พวกเขา (ฉันเพิ่งเพิ่มแท็กfindstr ด้วยตัวเอง)
Alan Moore

2
อืมใช่ฉันพบตอนนี้หนึ่งในความคิดเห็นของเขาในโพสต์ ฉันเห็น Regex ในชื่อ ยังไงก็ตามถ้าใครพบว่าโพสต์นี้เมื่อค้นหาเหมือนกันสำหรับการแสดงออกปกติเช่นผมอาจจะอาจจะเป็นประโยชน์กับคน :) ขอบคุณสำหรับความคิดเห็น
Aleks

15

จับคู่กับรูปแบบและใช้ภาษาโฮสต์เพื่อกลับผลลัพธ์บูลีนของการจับคู่ นี้จะชัดเจนมากขึ้นและบำรุงรักษาได้


1
จากนั้นฉันก็จบลงด้วย (~ A หรือ B) แทน (A และ ~ B) มันไม่ได้แก้ปัญหาของฉัน
notnot

1
รหัสเทียม: String toTest; if (toTest.matches (A) AND! toTest.matches (B)) {... }
Ben S

ฉันควรจะชัดเจนมากขึ้น - ชิ้นส่วนไม่อิสระอย่างเต็มที่ ถ้า A ตรงกับส่วนของสตริงเราจะสนใจว่า ~ B ตรงกับส่วนที่เหลือของสตริงนั้น (แต่ไม่จำเป็นต้องเป็นทั้งหมด) นี่คือฟังก์ชั่นบรรทัดคำสั่ง windows findstr ซึ่งฉันพบจะถูก จำกัด regex จริงดังนั้นจุดที่สงสัย
notnot

8

โปรดอย่ารื้อฟื้นคำถามโบราณนี้อีกครั้งเพราะมีวิธีแก้ปัญหาง่ายๆที่ไม่ได้กล่าวถึง (พบคำถามของคุณในขณะทำการค้นคว้าเพื่อค้นหาค่าหัว regex )

ฉันต้องเผชิญกับสถานการณ์ที่ต้องจับคู่รูปแบบ (A และ ~ B)

regex ขั้นพื้นฐานสำหรับเรื่องนี้เป็นเรื่องง่ายที่น่ากลัว: B|(A)

คุณเพียงแค่ไม่สนใจการจับคู่โดยรวมและตรวจสอบการจับกลุ่มที่ 1 ซึ่งจะมี A

ตัวอย่าง (ที่มีข้อจำกัดความรับผิดชอบทั้งหมดเกี่ยวกับการแยกวิเคราะห์ html ใน regex): A คือดิจิต, B คือดิจิตัลภายใน <a tag

Regex: <a.*?<\/a>|(\d+)

การสาธิต (ดูที่กลุ่ม 1 ในบานหน้าต่างด้านขวาล่าง)

การอ้างอิง

วิธีจับคู่รูปแบบยกเว้นในสถานการณ์ s1, s2, s3

วิธีจับคู่รูปแบบยกเว้น ...


ฟังดูดีเกินกว่าที่จะเป็นจริง! แต่น่าเสียดายที่การแก้ปัญหานี้ไม่เป็นสากลและจะล้มเหลวใน Emacs แม้หลังจากเปลี่ยนด้วย\d การอ้างอิงแรกกล่าวถึงเฉพาะกับ Perl และ PHP: "มีรูปแบบการใช้ไวยากรณ์เฉพาะกับ Perl และ PHP ที่ทำได้เหมือนกัน" [[:digit:]]
miguelmorin

4

ความสมบูรณ์ของภาษาปกติก็เป็นภาษาปกติเช่นกัน แต่ในการสร้างคุณต้องสร้างDFAสำหรับภาษาปกติและทำการเปลี่ยนแปลงสถานะที่ถูกต้องให้เป็นข้อผิดพลาด ดูนี้เป็นตัวอย่าง สิ่งที่หน้าไม่ได้พูดก็คือว่ามันแปลงลงใน/(ac|bd)/ /(a[^c]?|b[^d]?|[^ab])/การแปลงจาก DFA กลับเป็นนิพจน์ทั่วไปนั้นไม่สำคัญ จะง่ายกว่าถ้าคุณสามารถใช้นิพจน์ทั่วไปที่ไม่เปลี่ยนแปลงและเปลี่ยนซีแมนทิกส์ในรหัสได้ตามที่แนะนำไว้ก่อนหน้านี้


2
ถ้าฉันจัดการกับ regex จริงนี่ก็จะเป็นสิ่งที่สงสัย ตอนนี้ดูเหมือนว่า Regex จะอ้างถึงพื้นที่ของการจับคู่รูปแบบที่คลุมเครือ CSG-ish (?) ซึ่งส่วนใหญ่สนับสนุน เนื่องจากฉันต้องการจับคู่ (A และ ~ B) จึงไม่มีวิธีลบการปฏิเสธและยังคงทำทั้งหมดในขั้นตอนเดียว
notnot

Lookahead ตามที่อธิบายไว้ข้างต้นจะได้ทำมันถ้า findstr ทำอะไรเกินกว่า DFA regex ที่แท้จริง สิ่งทั้งหมดนั้นแปลกและฉันไม่รู้ว่าทำไมฉันต้องทำแบบบรรทัดคำสั่ง (แบทช์ตอนนี้) มันเป็นเพียงอีกตัวอย่างหนึ่งของการผูกมือฉัน
notnot

1
@notnot: คุณใช้ findstr จาก Windows อยู่ใช่ไหม จากนั้นคุณก็ต้อง / v ไลค์: findstr A inputfile | findstr / v B> outputfile.txt ตัวแรกจับคู่ทุกบรรทัดด้วย A, ตัวที่สองจับคู่ทุกบรรทัดที่ไม่มี B
Juliano

ขอบคุณ! นั่นคือสิ่งที่ฉันต้องการจริงๆ ฉันไม่ได้ถามคำถามแบบนั้น แต่ฉันก็ยังให้คำตอบกับ Gumbo สำหรับคำตอบทั่วไป
notnot

1

รูปแบบ - อีกครั้ง

str.split(/re/g) 

จะคืนค่าทุกอย่างยกเว้นรูปแบบ

ทดสอบที่นี่


คุณอาจต้องการพูดถึงว่าคุณต้องเข้าร่วมอีกครั้ง
tomdemuyt

วิธีการที่คล้ายกันคือใช้replace str.replace(/re/g, '')แล้วไม่จำเป็นต้องเข้าร่วมอีกครั้ง ถ้าคุณขว้างท้าย \ s อย่างนั้นล่ะ? เช่นstr.replace(/\re\s?/g, '')นั้นคุณจะกำจัดช่องว่างที่ซ้ำซ้อนที่คุณจะได้รับจากสิ่งที่ถูกแทนที่กลางสตริง
jakecraige

0

คำตอบของฉันที่นี่อาจช่วยแก้ปัญหาของคุณได้เช่นกัน:

https://stackoverflow.com/a/27967674/543814

  • แทนที่จะแทนที่คุณจะใช้การจับคู่
  • แทนของกลุ่มคุณจะอ่านกลุ่ม$1$2
  • กลุ่ม$2ถูกจับที่นั่นซึ่งคุณจะหลีกเลี่ยง

ตัวอย่าง:

Regex.Match("50% of 50% is 25%", "(\d+\%)|(.+?)");

กลุ่มการจับภาพแรกระบุรูปแบบที่คุณต้องการหลีกเลี่ยง กลุ่มการจับภาพล่าสุดจับทุกอย่างอื่น เพียงแค่อ่านกลุ่ม$2นั้น


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