"การจับคู่แบบผกผัน" กับนิพจน์ทั่วไปได้อย่างไร


112

ฉันใช้ RegexBuddy แต่ฉันก็มีปัญหากับสิ่งนี้: \

ฉันกำลังประมวลผลทีละบรรทัดไฟล์ ฉันสร้าง "แบบจำลองเส้น" เพื่อให้ตรงกับสิ่งที่ฉันต้องการ

ตอนนี้ฉันต้องการจับคู่แบบผกผัน ... คือฉันต้องการจับคู่บรรทัดที่มีสตริง 6 ตัวอักษร แต่ถ้าตัวอักษรหกตัวนี้ไม่ใช่ Andreaฉันจะทำอย่างไร?


แก้ไข:ฉันจะเขียนโปรแกรมที่ใช้ regex นี้ฉันยังไม่รู้ว่าใน python หรือ php ฉันกำลังทำสิ่งนี้ก่อนเพื่อเรียนรู้ regex :) มีบรรทัดประเภทต่างๆฉันต้องการใช้ regex เพื่อเลือกประเภทที่ฉันสนใจเมื่อฉันได้บรรทัดเหล่านี้แล้วฉันจะใช้ตัวกรองอื่นเพื่อไม่ให้ตรงกับค่าที่ทราบฉันต้องการตัวกรองอื่น ๆ ทั้งหมดไม่ใช่อย่างนั้น (?! ไม่ต้องการ) ทำงานได้ดีขอบคุณ :-)

ฉันหวังว่านี่จะทำให้คำถามกระจ่างขึ้น :)


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

คำตอบ:


70
(?!Andrea).{6}

สมมติว่าเอ็นจิ้น regexp ของคุณสนับสนุนคนมองเชิงลบ ..

แก้ไข: .. หรือคุณอาจต้องการใช้[A-Za-z]{6}แทน.{6}

แก้ไข (อีกครั้ง): โปรดทราบว่าโดยทั่วไป lookaheads และ lookbehinds ไม่ใช่วิธีที่ถูกต้องในการ "ผกผัน" การจับคู่นิพจน์ทั่วไป Regexps ไม่ได้ถูกตั้งค่าสำหรับการจับคู่เชิงลบจริงๆพวกเขาปล่อยให้เป็นภาษาใดก็ตามที่คุณใช้ด้วย


คุณต้องเพิ่ม ^ ที่ @Vinko Vrsalovic ใช้จึงจะไม่ตรงกับ "ndrea \ n"
61

2
. ไม่ตรงกับ \ n โดยค่าเริ่มต้น (บางภาษา [เช่น Perl] อนุญาตให้คุณเปิดพฤติกรรมนั้นได้ แต่โดยค่าเริ่มต้นจะตรงกับทุกอย่าง แต่ \ n)
แดน

1
(บวก OP ไม่เคยพูดถึงสตริงที่จะต้องเกิดขึ้นที่จุดเริ่มต้นของบรรทัด)
แดน

1
คุณหมายถึงอะไรสำหรับ OP?
Andrea Ambu

1
Andrea: OP แปลว่า "ผู้โพสต์ต้นฉบับ" ดังนั้นฉันหมายถึงคุณ :)
Dan

47

สำหรับ Python / Java

^(.(?!(some text)))*$

http://www.lisnichenko.com/articles/javapython-inverse-regex.html


4
วิธีนี้ใช้ไม่ได้ คุณกำลังคิดถึงสำนวนโทเค็น Tempered Greedy แต่จุดจะต้องตามหลัง Lookahead ไม่ใช่ก่อนหน้านี้ ดูคำถามนี้ แต่วิธีการนั้นเกินความจำเป็นสำหรับงานนี้อยู่ดี
Alan Moore

ไม่รู้ว่าเขียนด้วยภาษาใด แต่ใช้งานได้เหมือนมีเสน่ห์ในข้อความ Sublime เพื่อล้างข้อมูลทดสอบของฉัน ขอบคุณ!
Matthias dirickx

1
@AlanMoore อันที่จริงมันเกือบจะใช้ได้กับกรณีการใช้งานนี้ อย่างไรก็ตามหากsome textเริ่มต้นบรรทัดจะส่งคืนผลลัพธ์ที่ไม่ถูกต้อง
Zenexer

2
@Zenexer นั่นคือสิ่งที่ฉันหมายถึง หากจุดอยู่หลัง Lookahead แทนที่จะเป็นจุดก่อนก็จะทำงานได้อย่างสมบูรณ์
Alan Moore

นี่คือลิงค์ที่อธิบายเพิ่มเติม ผมไม่เข้าใจว่าทำไมและไม่เพียง?! !
Timo

21

อัปเดตพร้อมข้อเสนอแนะจากAlan Moore

ใน PCRE และตัวแปรที่คล้ายกันคุณสามารถสร้าง regex ที่ตรงกับบรรทัดใดก็ได้ที่ไม่มีค่า:

^(?:(?!Andrea).)*$

นี้เรียกว่าอารมณ์โลภโทเค็น ข้อเสียคือทำหน้าที่ได้ไม่ดี


1
นี่คือโทเค็น Tempered Greedy ในรูปแบบยาว เพียงแค่ใส่จุด (หรือ[\s\S]ซึ่งมีประโยชน์ใน JavaScript เท่านั้น) ต่อจาก Lookahead ที่สองและคุณไม่จำเป็นต้องมีอันแรก: ^(?:(?!Andrea).)*$.
Alan Moore

@AlanMoore ดี! ฉันไม่พบรูปแบบที่เป็นที่ยอมรับที่ได้ผลเช่นนั้นดังนั้นฉันจึงคิดขึ้นมาเอง แทนที่จะให้ฉันตอบคุณควรให้สิ่งนั้นเป็นของคุณเอง
Zenexer

ไม่เป็นไรมีคำตอบที่ดีมากมายอยู่แล้ว และคุณสมควรได้รับเครดิตสำหรับการประดิษฐ์สำนวนด้วยตัวคุณเอง ไชโย!
Alan Moore

ทำไมคุณถึงแนะนำให้ใช้[\S\s]? OP กำลังพูดถึงการจับคู่บรรทัดที่ไม่มีคำว่า "Andrea" ไม่เกี่ยวกับการตรวจสอบว่าทั้งสตริงมีคำนี้หรือไม่ ฉันพลาดอะไรไปรึเปล่า?
x-yuri

@ x-yuri ฉันคิดว่าคุณพูดถูก ฉันอาจจะตอบคำถามที่เคยได้คือฉันเข้าชมหน้านี้เป็นครั้งแรกโดยไม่สนใจความแตกต่าง การเชื่อมต่อของฉันไม่ดีพอที่จะอัปเดตคำตอบในตอนนี้แม้ว่า (<10 kbps)
Zenexer

11

คุณใช้ภาษาอะไร ความสามารถและไวยากรณ์ของการใช้งาน regex มีความสำคัญสำหรับสิ่งนี้

คุณสามารถใช้การมองไปข้างหน้า ใช้ python เป็นตัวอย่าง

import re

not_andrea = re.compile('(?!Andrea)\w{6}', re.IGNORECASE)

เพื่อทำลายสิ่งนั้น:

(?! Andrea)หมายถึง 'จับคู่ถ้าอักขระ 6 ตัวถัดไปไม่ใช่ "Andrea"'; ถ้าเป็นเช่นนั้น

\ wหมายถึง "อักขระคำ" - อักขระที่เป็นตัวเลขและตัวอักษร เทียบเท่ากับคลาส [a-zA-Z0-9_]

\ w {6}หมายถึงอักขระ 6 คำ

re.IGNORECASEหมายความว่าคุณจะยกเว้น "Andrea", "andrea", "ANDREA" ...

อีกวิธีหนึ่งคือใช้ตรรกะโปรแกรมของคุณ - ใช้บรรทัดทั้งหมดที่ไม่ตรงกับ Andrea และวางไว้ใน regex ที่สองเพื่อตรวจสอบอักขระ 6 ตัว หรือก่อนอื่นให้ตรวจสอบอักขระคำศัพท์อย่างน้อย 6 ตัวจากนั้นตรวจสอบว่าไม่ตรงกับ Andrea


7

การยืนยันผู้มองในแง่ลบ

(?!Andrea)

นี่ไม่ใช่การจับคู่แบบกลับหัว แต่เป็นวิธีที่ดีที่สุดที่คุณสามารถทำได้โดยตรงกับ regex ไม่ใช่ทุกแพลตฟอร์มที่รองรับ


1
จนกว่าผู้ถามจะชี้แจงฉันไม่เห็นว่าการแข่งขันจะต้องเริ่มต้นที่จุดเริ่มต้นของบรรทัด แล้วทำไม ^?
Hamish Downer

เพราะฉันเข้าใจว่าเขาต้องการตรวจสอบที่จุดเริ่มต้นของบรรทัดแก้ไขให้คำชี้แจง
Vinko Vrsalovic

5

หากคุณต้องการทำสิ่งนี้ใน RegexBuddy มีสองวิธีในการรับรายการบรรทัดทั้งหมดที่ไม่ตรงกับนิพจน์ทั่วไป

บนแถบเครื่องมือบนแผงทดสอบตั้งค่าขอบเขตการทดสอบเป็น "ทีละบรรทัด" เมื่อคุณทำเช่นนั้นรายการ List All Lines ที่ไม่มีการจับคู่จะปรากฏใต้ปุ่ม List All บนแถบเครื่องมือเดียวกัน (หากคุณไม่เห็นปุ่มรายการทั้งหมดให้คลิกปุ่มจับคู่ในแถบเครื่องมือหลัก)

ในแผง GREP คุณสามารถเปิดช่องทำเครื่องหมาย "ตามบรรทัด" และ "กลับด้านผลลัพธ์" เพื่อรับรายการบรรทัดที่ไม่ตรงกันในไฟล์ที่คุณกำลังคัดลอก


5

(?!มีประโยชน์ในทางปฏิบัติ แม้ว่าจะพูดอย่างเคร่งครัด แต่การมองไปข้างหน้าไม่ใช่การแสดงออกปกติตามที่กำหนดไว้ในทางคณิตศาสตร์

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

นี่คือโปรแกรมคำนวณผลลัพธ์โดยอัตโนมัติ ผลลัพธ์ของมันคือเครื่องจักรที่สร้างขึ้นซึ่งมักจะซับซ้อนกว่าการเขียนด้วยมือ แต่ผลการทำงาน


1

ฉันเพิ่งคิดวิธีนี้ซึ่งอาจใช้ฮาร์ดแวร์มาก แต่ใช้งานได้:

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

นี่คือ oneliner:

notMatched = re.sub(regex, "", string)

ฉันใช้สิ่งนี้เพราะฉันถูกบังคับให้ใช้ regex ที่ซับซ้อนมากและไม่สามารถหาวิธีกลับด้านในทุกส่วนได้ภายในระยะเวลาที่เหมาะสม

สิ่งนี้จะส่งคืนผลลัพธ์สตริงให้คุณเท่านั้นไม่ใช่วัตถุที่ตรงกัน!


-3

ใน perl คุณสามารถทำได้

กระบวนการ ($ line) if ($ line = ~! / Andrea /);


4
ไวยากรณ์นั้นผิด ฉันคิดว่าคุณหมายถึงกระบวนการ ($ line) ถ้า $ line! ~ / Andrea /
dland
โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.