Regex สำหรับสตริงที่ไม่ลงท้ายด้วยคำต่อท้ายที่กำหนด


190

ฉันไม่สามารถค้นหา regex ที่เหมาะสมเพื่อจับคู่สตริงใด ๆ ที่ไม่ลงท้ายด้วยเงื่อนไขบางอย่าง aตัวอย่างเช่นผมไม่ต้องการที่จะตรงกับสิ่งที่สิ้นสุดกับ

นัดนี้

b
ab
1

สิ่งนี้ไม่ตรงกัน

a
ba

ฉันรู้ว่า regex ควรลงท้ายด้วย$เพื่อทำเครื่องหมายจุดสิ้นสุดแม้ว่าฉันไม่ทราบว่าควรนำหน้าอะไร

แก้ไข : คำถามเดิมดูเหมือนจะไม่เป็นตัวอย่างที่ถูกต้องสำหรับกรณีของฉัน ดังนั้นวิธีจัดการกับตัวละครมากกว่าหนึ่งตัว? พูดอะไรไม่จบด้วยabเหรอ?

ฉันสามารถแก้ไขได้โดยใช้หัวข้อนี้ :

.*(?:(?!ab).).$

แม้ว่าข้อเสียของสิ่งนี้คือมันไม่ตรงกับสายอักขระหนึ่งตัว


5
นี่ไม่ใช่คำถามที่เชื่อมโยงซ้ำ - การจับคู่กับเฉพาะจุดสิ้นสุดนั้นต้องใช้ไวยากรณ์ที่แตกต่างจากการจับคู่ที่ใดก็ได้ภายในสตริง ลองดูคำตอบยอดนิยมที่นี่
jaustin

ฉันยอมรับว่านี่ไม่ใช่คำถามที่เชื่อมโยงกัน ฉันสงสัยว่าเราจะลบ "เครื่องหมาย" ด้านบนได้อย่างไร
Alan Cabrera

ไม่มีลิงก์ดังกล่าวที่ฉันเห็น
Alan Cabrera

คำตอบ:


252

คุณไม่ได้ให้ภาษาแก่เรา แต่ถ้าการสนับสนุนรสชาติ regex ของคุณดูอยู่เบื้องหลังการยืนยันนี่คือสิ่งที่คุณต้องการ:

.*(?<!a)$

(?<!a)เป็นการยืนยันเมื่อตรวจสอบที่ทำให้แน่ใจว่าก่อนที่จะสิ้นสุดของสตริง (หรือแถวที่มีmตัวดัดแปลง) ไม่มีอักขระ "a"

ดูที่นี่ใน Regexr

คุณสามารถขยายสิ่งนี้กับตัวละครอื่น ๆ ได้อย่างง่ายดายเนื่องจากการตรวจสอบสตริงและไม่ใช่คลาสอักขระ

.*(?<!ab)$

สิ่งนี้จะจับคู่สิ่งที่ไม่ได้ลงท้ายด้วย "ab" ดูได้จาก Regexr


1
ฉันไม่รู้จัก RegexPAL แต่ regexes นั้นมีความแตกต่างกันในทุกภาษาและการมองหาสิ่งที่เป็นคุณสมบัติขั้นสูงที่ไม่ได้รับการสนับสนุนจากทุกคน
stema

7
regexpal เป็นจาวาสคริปต์ตาม regex ทดสอบและ JavaScript ไม่สนับสนุนการยืนยัน lookbehind ซึ่งเป็นเรื่องน่าเศร้า
Hamza

Lookbehinds ไม่ได้รับการสนับสนุนบน regexr (javascript)
Stealth Rabbi

1
การขาด lookbehinds ใน JS ทำให้ฉันร้องไห้ หากคุณกำลังทำฝั่งเซิร์ฟเวอร์แม้ว่าคุณอาจจะสามารถใช้โมดูล PCRE บน NPM หรือคล้ายกันเพื่อใช้โดยตรง (เป็นชุดของการผูกข้อมูลดังนั้นฉันไม่คิดว่าคุณจะใช้ front-end ได้)
Eirik Birkeland

ประเภทของ lookahead / lookbehind ยืนยันเพิ่มเติม: stackoverflow.com/q/2973436/12484
Jon Schneider

76

ใช้สัญลักษณ์ไม่ ( ^):

.*[^a]$

หากคุณใส่^สัญลักษณ์ไว้ที่จุดเริ่มต้นของวงเล็บนั่นหมายความว่า "ทุกอย่างยกเว้นสิ่งที่อยู่ในวงเล็บ" $เป็นเพียงจุดยึดจนถึงที่สุด

สำหรับตัวละครหลายตัวให้ใส่พวกมันทั้งหมดในชุดตัวละครของตัวเอง:

.*[^a][^b]$

1
+1 โดยมีข้อแม้ว่าสิ่งนี้ไม่ตรงกับสตริงว่าง (ซึ่งอาจหรืออาจจะไม่ได้ตั้งใจ) ดังนั้นความหมายจึงค่อนข้าง "อักขระใด ๆ ที่ไม่ได้อยู่ในวงเล็บ"
Fred Foo

3
@ 0A0D: สตริงที่มีช่องว่างไม่ใช่สตริงว่าง
Fred Foo

7
@ 0A0D ที่จริงแล้วนั่นไม่ได้ขึ้นอยู่กับการถกเถียงนั่นเป็นเรื่องจริง
tckmn

8
@Doorknob: ที่ไม่ตรงหรือae cb
Fred Foo

1
ไม่, สิ่งนี้จะไม่อนุญาต "acb" เช่นกัน
Menno

49

ในการค้นหาไฟล์ที่ไม่ลงท้ายด้วย ".tmp" เราใช้ regex ต่อไปนี้:

^(?!.*[.]tmp$).*$

ทดสอบกับRegex Tester แล้วให้ผลลัพธ์ต่อไปนี้:

ป้อนคำอธิบายรูปภาพที่นี่


1
มันน่าสนใจความคิดใด ๆ ว่าทำไมถึงได้ผลและทำไมถึง^.*(?![.]tmp$)ไม่ได้
Łukasz Zaroda

4
ต้นของคุณ.*ตรงกับสตริงทั้งหมดแล้วดังนั้นการยกเว้นที่เหลืออยู่จะไม่ทำงานอีกต่อไป
FiveO

สำหรับวัตถุประสงค์ของฉันสิ่งนี้ใช้ได้ผลและคำตอบอื่น ๆ ก็ไม่ได้ ขอบคุณ!
David Moritz

8
.*[^a]$

regex aข้างต้นจะตรงกับสายที่ไม่ได้ลงท้ายด้วย


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

5

ลองสิ่งนี้

/.*[^a]$/

[]หมายถึงตัวอักษรชั้นเรียนและ^ตีความตัวละครคลาสเพื่อให้ตรงกับทุกอย่าง aแต่


1

คำถามเก่า แต่ฉันไม่สามารถหาทางออกที่ดีกว่าที่ฉันโพสต์ของฉันที่นี่ ค้นหาไดรฟ์ USB ทั้งหมด แต่ไม่แสดงรายการพาร์ติชันจึงลบ "ส่วน [0-9]" ออกจากผลลัพธ์ ฉันลงเอยด้วยการทำ grep สองตัวตัวสุดท้ายลบล้างผลลัพธ์

ls -1 /dev/disk/by-path/* | grep -P "\-usb\-" | grep -vE "part[0-9]*$"

ผลลัพธ์นี้ในระบบของฉัน:

pci-0000:00:0b.0-usb-0:1:1.0-scsi-0:0:0:0

ถ้าฉันต้องการพาร์ทิชันที่ฉันสามารถทำได้:

ls -1 /dev/disk/by-path/* | grep -P "\-usb\-" | grep -E "part[0-9]*$"

ที่ฉันได้รับ:

pci-0000:00:0b.0-usb-0:1:1.0-scsi-0:0:0:0-part1
pci-0000:00:0b.0-usb-0:1:1.0-scsi-0:0:0:0-part2

และเมื่อฉัน:

readlink -f /dev/disk/by-path/pci-0000:00:0b.0-usb-0:1:1.0-scsi-0:0:0:0

ฉันเข้าใจ:

/dev/sdb

1

คำตอบที่ยอมรับนั้นใช้ได้ถ้าคุณสามารถใช้ lookarounds อย่างไรก็ตามยังมีวิธีอื่นในการแก้ปัญหานี้

ถ้าเราดู regex ที่นำเสนออย่างกว้างขวางสำหรับคำถามนี้:

.*[^a]$

เราจะพบว่ามันใช้งานได้เกือบ ไม่ยอมรับสตริงว่างซึ่งอาจไม่สะดวกเล็กน้อย อย่างไรก็ตามนี่เป็นปัญหาเล็กน้อยเมื่อจัดการกับตัวละครเพียงตัวเดียว อย่างไรก็ตามหากเราต้องการยกเว้นสตริงทั้งหมดเช่น "abc" ดังนั้น:

.*[^a][^b][^c]$

จะไม่ทำ มันจะไม่ยอมรับ ac เช่น

มีวิธีแก้ปัญหาที่ง่ายสำหรับปัญหานี้ เราสามารถพูดได้ว่า:

.{,2}$|.*[^a][^b][^c]$

รุ่นทั่วไปหรือมากกว่า:

.{,n-1}$|.*[^firstchar][^secondchar]$ ที่ n คือความยาวของสตริงที่คุณต้องการห้าม (สำหรับabcมัน 3), และfirstchar, secondchar... เป็นครั้งแรกที่ตัวละครสอง ... n ของสตริงของคุณ ( abcมันจะaแล้วbแล้วc)

สิ่งนี้มาจากการสังเกตอย่างง่าย ๆ ว่าสตริงที่สั้นกว่าข้อความที่เราไม่ห้ามไม่สามารถมีข้อความนี้ได้ตามคำจำกัดความ ดังนั้นเราสามารถยอมรับอะไรก็ได้ที่สั้นกว่า ("ab" ไม่ใช่ "abc") หรืออะไรก็ตามที่นานพอที่เราจะยอมรับ แต่ไม่จบ

นี่คือตัวอย่างของการค้นหาที่จะลบไฟล์ทั้งหมดที่ไม่ใช่. jpg:

find . -regex '.{,3}$|.*[^.][^j][^p][^g]$' -delete


.{,2}$|.*[^a][^b][^c]$ไม่ตรงกันccc
psalaets

0

อะไรก็ตามที่ตรงกับบางสิ่งที่ลงท้ายด้วย --- .*a$ดังนั้นเมื่อคุณจับคู่กับ regex ให้ปฏิเสธเงื่อนไขหรืออีกวิธีหนึ่งคุณสามารถทำใน.*[^a]$กรณีที่มีความ[^a]หมายอะไรnot a


0

หากคุณกำลังใช้งานgrepหรือsedไวยากรณ์จะแตกต่างกันเล็กน้อย ขอให้สังเกตว่า[^a][^b]วิธีการเรียงลำดับไม่ทำงานที่นี่:

balter@spectre3:~$ printf 'jd8a\n8$fb\nq(c\n'
jd8a
8$fb
q(c
balter@spectre3:~$ printf 'jd8a\n8$fb\nq(c\n' | grep ".*[^a]$"
8$fb
q(c
balter@spectre3:~$ printf 'jd8a\n8$fb\nq(c\n' | grep ".*[^b]$"
jd8a
q(c
balter@spectre3:~$ printf 'jd8a\n8$fb\nq(c\n' | grep ".*[^c]$"
jd8a
8$fb
balter@spectre3:~$ printf 'jd8a\n8$fb\nq(c\n' | grep ".*[^a][^b]$"
jd8a
q(c
balter@spectre3:~$ printf 'jd8a\n8$fb\nq(c\n' | grep ".*[^a][^c]$"
jd8a
8$fb
balter@spectre3:~$ printf 'jd8a\n8$fb\nq(c\n' | grep ".*[^a^b]$"
q(c
balter@spectre3:~$ printf 'jd8a\n8$fb\nq(c\n' | grep ".*[^a^c]$"
8$fb
balter@spectre3:~$ printf 'jd8a\n8$fb\nq(c\n' | grep ".*[^b^c]$"
jd8a
balter@spectre3:~$ printf 'jd8a\n8$fb\nq(c\n' | grep ".*[^b^c^a]$"

FWIW ฉันพบผลลัพธ์เดียวกันในRegex101ซึ่งฉันคิดว่าเป็นไวยากรณ์ JavaScript

ไม่ดี: https://regex101.com/r/MJGAmX/2
ดี: https://regex101.com/r/LzrIBu/2

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