วิธีการจับคู่“ มีอะไรจนถึงชุดลำดับของอักขระนี้” ในนิพจน์ทั่วไป


514

ใช้นิพจน์ทั่วไปนี้: /^[^abc]/. สิ่งนี้จะจับคู่อักขระเดี่ยวใด ๆ ที่จุดเริ่มต้นของสตริงยกเว้น a, b หรือ c

ถ้าคุณเพิ่ม*หลังจากที่มัน - /^[^abc]*/- การแสดงออกปกติจะยังคงเพิ่มตัวละครแต่ละตัวภายหลังจากผลจนมันตรงกับอย่างใดอย่างหนึ่งa, หรือ b , หรือ c

ตัวอย่างเช่นกับสตริงแหล่งที่มาของการแสดงออกจะตรงกับ"qwerty qwerty whatever abc hello""qwerty qwerty wh"

แต่ถ้าฉันต้องการให้สายอักขระตรงกัน "qwerty qwerty whatever "

... กล่าวอีกนัยหนึ่งฉันจะจับคู่ทุกอย่างให้ตรงกับ (แต่ไม่รวม) ลำดับที่แน่นอนได้ "abc"อย่างไร


คุณหมายถึงmatch but not includingอะไร
โตโต้

5
ฉันหมายถึงฉันต้องการจับคู่"qwerty qwerty whatever "- ไม่รวม "abc" ในคำอื่น ๆ ที่ฉันไม่"qwerty qwerty whatever abc"ต้องการการแข่งขันที่เกิดขึ้นจะเป็น
callum

2
ใน JavaScript do string.split('abc')[0]ที่คุณสามารถเพียงแค่ แน่นอนว่าไม่ใช่คำตอบอย่างเป็นทางการสำหรับปัญหานี้ แต่ฉันพบว่ามันตรงไปตรงมามากกว่า regex
Wylliam Judd

คำตอบ:


1020

คุณไม่ได้ระบุว่า regex รสชาติใดที่คุณใช้ แต่สิ่งนี้จะใช้ได้กับสิ่งที่ได้รับความนิยมมากที่สุดที่สามารถพิจารณาว่า "สมบูรณ์"

/.+?(?=abc)/

มันทำงานอย่างไร

.+? ส่วนหนึ่งเป็นรุ่นที่ยกเลิกโลภของ .+ (หนึ่งหรือมากกว่าของอะไร) เมื่อเราใช้.+เครื่องยนต์โดยทั่วไปจะจับคู่ทุกอย่าง จากนั้นถ้ามีอย่างอื่นใน regex มันจะย้อนกลับไปในขั้นตอนที่พยายามจับคู่ส่วนต่อไปนี้ นี่คือความ โลภพฤติกรรมที่มีความหมายมากที่สุดเท่าที่เป็นไปได้ที่จะตอบสนอง

เมื่อใช้ .+?แทนการจับคู่ทั้งหมดในครั้งเดียวและกลับไปหาเงื่อนไขอื่น ๆ (ถ้ามี) เครื่องยนต์จะจับคู่อักขระถัดไปทีละขั้นจนกว่าส่วนต่อไปของ regex จะถูกจับคู่ (อีกครั้งถ้ามี) นี่คือการยกเลิกการโลภความหมายการแข่งขัน ที่เป็นไปได้น้อยที่สุดเพื่อตอบสนองความ

/.+X/  ~ "abcXabcXabcX"        /.+/  ~ "abcXabcXabcX"
          ^^^^^^^^^^^^                  ^^^^^^^^^^^^

/.+?X/ ~ "abcXabcXabcX"        /.+?/ ~ "abcXabcXabcX"
          ^^^^                          ^

ต่อไปนี้ที่เรามี การ ยืนยันความกว้างศูนย์เป็น รอบ ๆ ดู สิ่งก่อสร้างที่จัดกลุ่มนี้ตรงกับเนื้อหา แต่ไม่นับเป็นตัวอักษรที่จับคู่ ( ความกว้างเป็นศูนย์ ) มันจะส่งกลับเฉพาะถ้าเป็นการแข่งขันหรือไม่ ( ยืนยัน )(?={contents})

ดังนั้นในแง่อื่น regex /.+?(?=abc)/หมายถึง:

จับคู่อักขระใด ๆ ให้น้อยที่สุดจนกว่าจะพบ "abc" โดยไม่นับ "abc"


12
สิ่งนี้อาจไม่ทำงานกับการขึ้นบรรทัดใหม่หากคาดว่าจะถูกดักจับ
einord

3
ความแตกต่างระหว่าง.+?และ.*คืออะไร
robbie

4
@ robbie0630 +หมายถึง 1 หรือมากกว่านั้นซึ่ง*หมายความว่า 0 หรือมากกว่า การรวม / ไม่รวม?จะทำให้โลภหรือไม่โลภ
jinglesthula

2
@ testerjoe2 /.+?(?=abc|xyz)/
JohnWrensby

4
ฉันสังเกตเห็นว่าสิ่งนี้ล้มเหลวในการเลือกสิ่งใดหากรูปแบบที่คุณมองหาไม่มีอยู่ แต่ถ้าคุณใช้^(?:(?!abc)(?!def).)*คุณสามารถโยงรูปแบบเพื่อแยกรูปแบบที่คุณไม่ต้องการและมันจะยังคงคว้าทุกอย่างตามที่ต้องการแม้ว่าจะไม่มีรูปแบบ
Karan Shishoo

122

หากคุณต้องการจับภาพทุกอย่างจนถึง "abc":

/^(.*?)abc/

คำอธิบาย:

( )จับภาพการแสดงออกในวงเล็บสำหรับการเข้าถึงการใช้$1, $2ฯลฯ

^ ตรงกับจุดเริ่มต้นของบรรทัด

.*จับคู่สิ่งที่?ไม่ใช่โลภ (ตรงกับจำนวนอักขระขั้นต่ำที่ต้องการ) - [1]

[1] เหตุผลที่จำเป็นต้องใช้สิ่งนี้คือสิ่งอื่นในสตริงต่อไปนี้:

whatever whatever something abc something abc

โดยค่าเริ่มต้น regexes เป็นโลภซึ่งหมายความว่ามันจะจับคู่ให้มากที่สุด ดังนั้น/^.*abc/จะจับคู่ "อะไรก็ตามสิ่งที่ตัวอักษร abc" การเพิ่มตัวบ่งชี้ที่ไม่โลภ?ทำให้ regex จับคู่ "อะไรก็ตามที่อะไรก็ตาม"


4
ขอบคุณ แต่อย่างหนึ่งของคุณไม่รวม abc ในการแข่งขัน กล่าวอีกนัยหนึ่งผลลัพธ์ที่ได้คือ "อะไรก็ตามที่ abc"
callum

1
คุณช่วยอธิบายสิ่งที่คุณพยายามจะทำในท้ายที่สุด หากสถานการณ์ของคุณคือ: (A) คุณต้องการให้ทุกสิ่งที่นำไปสู่ ​​"abc" เพียงใช้วงเล็บในสิ่งที่คุณต้องการดักจับ (B) คุณต้องการจับคู่สตริงจนถึง "abc" - คุณต้องตรวจสอบ abc ต่อไปดังนั้นจึงจำเป็นต้องเป็นส่วนหนึ่งของ regex โดยไม่คำนึงถึง คุณสามารถตรวจสอบว่ามีอะไรอีกบ้าง
Jared Ng

sedดูเหมือนจะไม่สนับสนุนการจับคู่ที่ไม่โลภและไม่สนับสนุนการมองไปรอบ ๆ ( (?=...)) ฉันจะทำอะไรได้อีก คำสั่งตัวอย่าง: echo "ONE: two,three, FOUR FIVE, six,seven" | sed -n -r "s/^ONE: (.+?), .*/\1/p"ส่งคืนtwo,three, FOUR FIVEแต่ฉันคาดว่าtwo,three...
CodeManX

1
@CoDEmanX คุณน่าจะโพสต์คำถามนั้นเป็นคำถามแยกต่างหากของคุณแทนที่จะเป็นความคิดเห็น การพูดถึงคำถามของคุณ: คุณอาจต้องการดูคำตอบของคำถามนี้ นอกจากนี้ยังทราบว่าในตัวอย่างของคุณไม่โลภล่ามตระหนักถึงจะกลับมาเพียงแค่ไม่two two,three
Jared Ng

3
นี่คือลักษณะที่คำตอบ regexp ทุกคนควรดู - ตัวอย่างและคำอธิบายของทุกส่วน ...
jave.web

54

ดังที่ @Jared Ng และ @Issun ชี้ให้เห็นกุญแจสำคัญในการแก้ปัญหาประเภทนี้ของ RegEx เช่น "จับคู่ทุกอย่างกับคำหรือสตริงย่อย" หรือ "จับคู่ทุกอย่างหลังจากคำหรือสตริงย่อย" เรียกว่า "lookaround" ความยาวเป็นศูนย์ . อ่านเพิ่มเติมเกี่ยวกับพวกเขาที่นี่

ในกรณีเฉพาะของคุณสามารถแก้ไขได้โดยมองในแง่ดีล่วงหน้า: .+?(?=abc)

ภาพที่มีค่าพันคำ. ดูคำอธิบายรายละเอียดในภาพหน้าจอ

ภาพหน้าจอของ Regex101


23
.+?(?=abc)regex ที่คัดลอกได้มีค่ามากกว่า
Tom

สิ่งที่เกี่ยวกับการยกเว้นช่องว่างนำ?
Royi

8

สิ่งที่คุณต้องการดูรอบ ๆ .+? (?=abc)ยืนยันเช่น

ดู: Lookahead และ Lookbehind ยืนยันความยาวเป็นศูนย์

โปรดทราบว่าไม่ได้เป็นเช่นเดียวกับ[abc] abcภายในวงเล็บไม่ใช่สตริง - ตัวละครแต่ละตัวเป็นเพียงหนึ่งในความเป็นไปได้ นอกวงเล็บจะกลายเป็นสตริง


7

สำหรับ regex ใน Java และฉันเชื่อว่าในเอนจิ้น regex ส่วนใหญ่หากคุณต้องการรวมส่วนสุดท้ายสิ่งนี้จะทำงาน:

.+?(abc)

ตัวอย่างเช่นในบรรทัดนี้:

I have this very nice senabctence

เลือกตัวละครทั้งหมดจนกระทั่ง "abc" และรวมถึง abc

ใช้ regex ของเราผลลัพธ์จะเป็น: I have this very nice senabc

ทดสอบสิ่งนี้: https://regex101.com/r/mX51ru/1


4

ฉันสิ้นสุดในคำถาม stackoverflow นี้หลังจากค้นหาความช่วยเหลือเพื่อแก้ไขปัญหาของฉัน แต่ไม่พบวิธีแก้ไข:

ดังนั้นฉันต้องพูดโพล่งออกมา ... หลังจากผ่านไประยะหนึ่งฉันก็สามารถไปถึง regex ที่ฉันต้องการ:

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

อย่างที่คุณเห็นฉันต้องการโฟลเดอร์ล่วงหน้าถึงหนึ่งโฟลเดอร์ "grp-bps" โดยไม่รวมเส้นประล่าสุด และจำเป็นต้องมีอย่างน้อยหนึ่งโฟลเดอร์หลังจากโฟลเดอร์ "grp-bps"

แก้ไข

เวอร์ชันข้อความสำหรับการคัดลอก (เปลี่ยน 'grp-bps' สำหรับข้อความของคุณ):

.*\/grp-bps\/[^\/]+

6
ไม่มีรุ่นข้อความใช่ไหม 🙄
kiradotee

2

นี่จะสมเหตุสมผลเกี่ยวกับ regex

  1. คำที่แน่นอนสามารถหาได้จากคำสั่ง regex ต่อไปนี้:

( "(. *?)") / g

ที่นี่เราสามารถหาคำที่แน่นอนทั่วโลกซึ่งอยู่ในเครื่องหมายคำพูดคู่ ตัวอย่างเช่นหากข้อความค้นหาของเราคือ

นี่คือตัวอย่างของคำที่ "ยกมาสองครั้ง"

จากนั้นเราจะได้รับ "การยกสองครั้ง" จากประโยคนั้น


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

1
สวัสดีฉันได้อธิบายวิธีการใช้คำหรือประโยคระหว่างตัวละครพิเศษ ที่นี่คำถามของเราก็คือ "อะไรก็ได้จนกว่าลำดับของอักขระพิเศษ" ดังนั้นฉันจึงลองด้วยเครื่องหมายคำพูดคู่และอธิบายที่นี่ ขอบคุณ
Ponmurugan Mohanraj

2

บนงูหลาม:

.+?(?=abc) ใช้งานได้กับเคสสายเดี่ยว

[^]+?(?=abc)ไม่ทำงานเนื่องจากไพ ธ อนไม่รู้จัก [^] ว่าเป็น regex ที่ถูกต้อง ในการทำให้การจับคู่หลายบรรทัดทำงานคุณจะต้องใช้ตัวเลือก re.DOTALL ตัวอย่างเช่น:

re.findall('.+?(?=abc)', data, re.DOTALL)

0

ฉันเชื่อว่าคุณต้องการคำสั่งย่อย ถ้าฉันจำได้ถูกต้องคุณสามารถใช้()วงเล็บปกติสำหรับนิพจน์ย่อย

ส่วนนี้มาจากคู่มือ grep:

 Back References and Subexpressions
       The back-reference \n, where n is a single digit, matches the substring
       previously matched  by  the  nth  parenthesized  subexpression  of  the
       regular expression.

ทำสิ่งที่ชอบ^[^(abc)]ควรทำเคล็ดลับ


ขออภัยนั่นไม่ได้ผล การใส่ตัวอักษร abc ไว้ในวงเล็บดูเหมือนจะไม่สร้างความแตกต่างเลย พวกเขายังคงเป็น "a หรือ b หรือ c"
callum

-1

$เครื่องหมายจุดสิ้นสุดของสตริงดังนั้นบางอย่างเช่นนี้ควรจะทำงาน: [[^abc]*]$ที่คุณกำลังมองหาสิ่งที่ไม่สิ้นสุดในการทำซ้ำใด ๆabcแต่มันจะต้องเป็นที่สิ้นสุด

นอกจากนี้หากคุณใช้ภาษาสคริปต์กับ regex (เช่น php หรือ js) พวกเขามีฟังก์ชั่นการค้นหาที่หยุดเมื่อพบรูปแบบครั้งแรก (และคุณสามารถระบุการเริ่มต้นจากด้านซ้ายหรือเริ่มจากด้านขวาหรือด้วย php คุณสามารถทำ implode เพื่อทำมิเรอร์สตริง)


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