ฉันมีค่าเช่นนี้
"Foo Bar" "Another Value" something else
regex ใดที่จะส่งคืนค่าที่อยู่ในเครื่องหมายคำพูด (เช่นFoo Bar
และAnother Value
)
ฉันมีค่าเช่นนี้
"Foo Bar" "Another Value" something else
regex ใดที่จะส่งคืนค่าที่อยู่ในเครื่องหมายคำพูด (เช่นFoo Bar
และAnother Value
)
คำตอบ:
ฉันใช้สิ่งต่อไปนี้กับความสำเร็จที่ยิ่งใหญ่:
(["'])(?:(?=(\\?))\2.)*?\1
สนับสนุนคำพูดซ้อนเช่นกัน
สำหรับผู้ที่ต้องการคำอธิบายที่ลึกซึ้งยิ่งขึ้นเกี่ยวกับวิธีการทำงานนี่คือคำอธิบายจากผู้ใช้ephemient :
([""'])
ตรงกับคำพูด;((?=(\\?))\2.)
หากมีแบ็กสแลชอยู่ให้กลืนมันและตรงกับตัวละครหรือไม่*?
จับคู่หลายครั้ง (ไม่ใช่ตะกละตะกลามไม่กินคำพูดปิด);\1
ตรงกับคำพูดเดียวกับที่ใช้สำหรับเปิด
"foo\"
กัน เคล็ดลับที่มองไปข้างหน้าทำให้?
หวงปริมาณ (แม้ว่ารสชาติ regex ไม่สนับสนุน?+
ไวยากรณ์หรือการจัดกลุ่มอะตอม)
(["'])(?:\\.|[^\\])*?\1
โดยทั่วไปแฟรกเมนต์นิพจน์ทั่วไปต่อไปนี้คือสิ่งที่คุณกำลังมองหา:
"(.*?)"
สิ่งนี้ใช้ความโลภ * หรือไม่? ผู้ประกอบการที่จะจับทุกอย่างถึง แต่ไม่รวมถึงคำพูดสองครั้งต่อไป จากนั้นคุณใช้กลไกเฉพาะภาษาเพื่อแยกข้อความที่ตรงกัน
ใน Python คุณสามารถทำได้:
>>> import re
>>> string = '"Foo Bar" "Another Value"'
>>> print re.findall(r'"(.*?)"', string)
['Foo Bar', 'Another Value']
"hello \" world"
"(.*?(?<!\\))"
ฉันจะไปเพื่อ:
"([^"]*)"
[^ "]เป็น regex สำหรับตัวอักษรใด ๆ ยกเว้น ' " '
เหตุผลที่ผมใช้นี้มากกว่าผู้ประกอบการจำนวนมากที่ไม่โลภคือว่าผมต้องให้มองว่าขึ้นเพียงเพื่อให้แน่ใจว่าฉันได้รับมันถูกต้อง
ให้ดูสองวิธีที่มีประสิทธิภาพที่จัดการกับคำพูดที่หลบหนี รูปแบบเหล่านี้ไม่ได้ออกแบบมาให้รัดกุมหรือสวยงาม แต่มีประสิทธิภาพ
วิธีการเหล่านี้ใช้การแบ่งแยกอักขระตัวแรกเพื่อค้นหาอัญประกาศอย่างรวดเร็วในสตริงโดยไม่มีค่าใช้จ่ายของการสลับ (ความคิดคือการทิ้งอักขระที่ไม่ได้อ้างอิงอย่างรวดเร็วโดยไม่ต้องทดสอบทั้งสองสาขาของการสลับ)
เนื้อหาระหว่างเครื่องหมายคำพูดจะอธิบายด้วยการวนซ้ำที่ไม่ได้ควบคุม (แทนที่จะสลับซ้ำ) เพื่อให้มีประสิทธิภาพมากขึ้นเช่นกัน: [^"\\]*(?:\\.[^"\\]*)*
เห็นได้ชัดว่าการจัดการกับสตริงที่ไม่มีคำพูดที่สมดุลคุณสามารถใช้ปริมาณที่เป็นเจ้าของแทน: [^"\\]*+(?:\\.[^"\\]*)*+
หรือวิธีแก้ปัญหาเพื่อเลียนแบบพวกเขาเพื่อป้องกันไม่ให้ย้อนกลับมากเกินไป คุณสามารถเลือกได้เช่นกันว่าชิ้นส่วนที่ยกมาสามารถเป็นเครื่องหมายคำพูดเปิดจนกระทั่งคำพูดถัดไป (ไม่หนี) หรือจุดสิ้นสุดของสตริง ในกรณีนี้ไม่จำเป็นต้องใช้ปริมาณที่เป็นเจ้าของคุณจะต้องทำให้การเสนอราคาล่าสุดเป็นทางเลือก
แจ้งให้ทราบล่วงหน้า: บางครั้งคำพูดจะไม่หนีด้วยแบ็กสแลช แต่ด้วยการทำซ้ำคำพูด ในกรณีนี้รูปแบบย่อยเนื้อหาจะมีลักษณะดังนี้:[^"]*(?:""[^"]*)*
รูปแบบหลีกเลี่ยงการใช้ของกลุ่มที่จับและ backreference (ผมหมายถึงสิ่งที่ต้องการ(["']).....\1
)และใช้การสลับที่เรียบง่าย แต่มี["']
ที่จุดเริ่มต้นในปัจจัย
Perl ชอบ:
["'](?:(?<=")[^"\\]*(?s:\\.[^"\\]*)*"|(?<=')[^'\\]*(?s:\\.[^'\\]*)*')
(โปรดทราบว่า(?s:...)
เป็นน้ำตาล syntactic เพื่อเปิดโหมด dotall / singleline ภายในกลุ่มที่ไม่ได้รับการสนับสนุนหากไม่รองรับไวยากรณ์นี้คุณสามารถเปิดโหมดนี้สำหรับรูปแบบทั้งหมดหรือเปลี่ยนจุดด้วย[\s\S]
)
(วิธีการเขียนรูปแบบนี้มีทั้งหมด "ขับเคลื่อนด้วยมือ" และไม่คำนึงถึงการเพิ่มประสิทธิภาพภายในของเครื่องยนต์ในที่สุด)
สคริปต์ ECMA:
(?=["'])(?:"[^"\\]*(?:\\[\s\S][^"\\]*)*"|'[^'\\]*(?:\\[\s\S][^'\\]*)*')
ขยาย POSIX:
"[^"\\]*(\\(.|\n)[^"\\]*)*"|'[^'\\]*(\\(.|\n)[^'\\]*)*'
หรือเพียงแค่:
"([^"\\]|\\.|\\\n)*"|'([^'\\]|\\.|\\\n)*'
/pattern/
โดยไม่ต้องหลบสิ่งใด ๆ (แทนที่จะเป็นรูปแบบของวัตถุnew RegExp("(?=[\"'])(?:\"[^\"\\\\]*...");
)
s
นี่: (?s:
และถ้าคุณใส่ที่(?s)
อื่นในรูปแบบ
RegEx ของคำตอบที่ยอมรับผลตอบแทนค่ารวมทั้งเครื่องหมายคำพูด sourrounding ของพวกเขา"Foo Bar"
และ"Another Value"
เป็นแมตช์
นี่คือ RegEx ที่คืนค่าเฉพาะระหว่างเครื่องหมายคำพูด (ตามที่ผู้ถามถูกถาม):
เครื่องหมายคำพูดคู่เท่านั้น (ใช้ค่าของกลุ่มการจับ # 1):
"(.*?[^\\])"
คำพูดเดียวเท่านั้น (ใช้ค่าของกลุ่มการจับ # 1):
'(.*?[^\\])'
ทั้งสอง (ใช้ค่าของกลุ่มการดักจับ # 2):
(["'])(.*?[^\\])\1
-
การสนับสนุนทั้งหมดหนีออกมาและซ้อนคำพูด
src="(.*)"
แต่เห็นได้ชัดว่ามันเลือกทุกอย่างก่อนสุดท้าย ", REGEX ของคุณ แต่เลือกเฉพาะเนื้อหา src =" "แต่ฉันไม่เข้าใจว่าอย่างไร
โดยเฉพาะไม่มีคำตอบใด ๆ ที่สร้าง regex ที่การจับคู่คืนคือข้อความในเครื่องหมายคำพูดซึ่งเป็นสิ่งที่ถูกถาม MA-Madden พยายาม แต่ได้รับการจับคู่เป็นกลุ่มจับมากกว่าการแข่งขันทั้งหมด วิธีหนึ่งในการทำเช่นนั้นจริง ๆ คือ:
(?<=(["']\b))(?:(?=(\\?))\2.)*?(?=\1)
ตัวอย่างนี้สามารถเห็นได้ในการสาธิตนี้https://regex101.com/r/Hbj8aP/1
กุญแจสำคัญในที่นี้คือการมองในเชิงบวกที่จุดเริ่มต้น (the ?<=
) และการมองที่เป็นบวกในตอนท้าย (the ?=
) lookbehind กำลังมองหาตัวอักษรปัจจุบันเพื่อตรวจสอบคำพูดถ้าพบแล้วเริ่มจากตรงนั้นแล้ว lookahead กำลังตรวจสอบตัวอักษรล่วงหน้าเพื่อหาคำพูดและถ้าพบหยุดอยู่กับตัวละครนั้น กลุ่ม lookbehind (the ["']
) ถูกห่อในวงเล็บเพื่อสร้างกลุ่มสำหรับคำพูดใด ๆ ที่พบในตอนเริ่มต้นจากนั้นจะถูกใช้ที่ lookahead ท้าย(?=\1)
เพื่อให้แน่ใจว่าจะหยุดเมื่อพบคำพูดที่สอดคล้องกันเท่านั้น
ภาวะแทรกซ้อนอื่น ๆ เท่านั้นคือเนื่องจาก lookahead ไม่ได้ใช้อัญประกาศจริง ๆ มันจะพบได้อีกครั้งโดย lookbehind เริ่มต้นซึ่งทำให้ข้อความระหว่างสิ้นสุดและราคาเริ่มต้นในบรรทัดเดียวกันที่จะจับคู่ การวางขอบเขตของคำบนเครื่องหมายคำพูดเปิด ( ["']\b
) ช่วยในเรื่องนี้ แต่โดยอุดมคติแล้วฉันต้องการเลื่อนผ่าน lookahead แต่ฉันไม่คิดว่าเป็นไปได้ บิตที่อนุญาตให้ตัวละครที่หลบหนีอยู่ตรงกลางฉันได้รับคำตอบจากอดัมโดยตรง
รูปแบบ(["'])(?:(?=(\\?))\2.)*?\1
ข้างต้นทำหน้าที่ได้ แต่ฉันกังวลกับการแสดงของมัน (มันไม่ได้แย่ แต่น่าจะดีกว่า) การขุดด้านล่างมันเร็วกว่า ~ 20%
รูปแบบ"(.*?)"
ไม่สมบูรณ์ คำแนะนำของฉันสำหรับทุกคนที่อ่านข้อความนี้ไม่ได้ใช้เลย !!!
ตัวอย่างเช่นมันไม่สามารถจับภาพสตริงจำนวนมาก (ถ้าจำเป็นฉันสามารถจัดทำกรณีทดสอบอย่างละเอียด) เช่นเดียวกับด้านล่าง:
$ string = 'สบายดีไหม ฉัน
\'
สบายดีขอบคุณ ';
ส่วนที่เหลือเป็นเพียง "ดี" ดังที่กล่าวข้างต้น
หากคุณสนใจทั้งในเรื่องประสิทธิภาพและความแม่นยำให้เริ่มจากด้านล่าง
/(['"])((\\\1|.)*?)\1/gm
ในการทดสอบของฉันมันครอบคลุมทุก ๆ สตริงที่ฉันพบ แต่ถ้าคุณพบบางสิ่งที่ไม่ทำงานฉันยินดีที่จะอัปเดตให้คุณ
ตรวจสอบรูปแบบของฉันในการทดสอบ regex ออนไลน์
ฉันชอบวิธีการแก้ปัญหาของ Eugen Mihailescuเพื่อจับคู่เนื้อหาระหว่างคำพูดในขณะที่อนุญาตให้หลีกเลี่ยงคำพูดได้ อย่างไรก็ตามฉันค้นพบปัญหาบางอย่างเกี่ยวกับการหลบหนีและเกิดขึ้นกับ regex ต่อไปนี้เพื่อแก้ไข:
(['"])(?:(?!\1|\\).|\\.)*\1
มันใช้กลอุบายและยังคงง่ายและดูแลรักษาง่าย
การสาธิต (โดยมีกรณีทดสอบเพิ่มเติมให้ใช้และขยายตัวได้)
PS: หากคุณต้องการเนื้อหาระหว่างเครื่องหมายคำพูดในการแข่งขันเต็มรูปแบบ ( $0
) และไม่กลัวการใช้บทลงโทษ:
(?<=(['"])\b)(?:(?!\1|\\).|\\.)*(?=\1)
น่าเสียดายที่ไม่มีเครื่องหมายอัญประกาศเป็นจุดยึดฉันต้องเพิ่มขอบเขต\b
ซึ่งไม่สามารถเล่นได้ดีกับช่องว่างและอักขระที่ไม่ใช่คำหลังจากตัวอ้างอิงเริ่มต้น
หรือแก้ไขเวอร์ชันเริ่มต้นโดยเพิ่มกลุ่มและแยกรูปแบบสตริง$2
:
(['"])((?:(?!\1|\\).|\\.)*)\1
PPS: ถ้าโฟกัสของคุณเป็นเพียงที่มีต่อประสิทธิภาพไปกับการแก้ปัญหาเมียร์เอ Hippolyte ของ ; มันเป็นสิ่งที่ดี
-
เช่นในพิกัดลองจิจูด
รุ่นนี้
ควบคุมการย้อนรอย
/(["'])((?:(?!\1)[^\\]|(?:\\\\)*\\[^\\])*)\1/
คำตอบเพิ่มเติม! นี่คือทางออกที่ฉันใช้
\"([^\"]*?icon[^\"]*?)\"
TLDR;
แทนที่ไอคอนคำด้วยสิ่งที่คุณมองหาในคำพูดและ voila!
วิธีการทำงานนี้คือการค้นหาคำหลักและไม่สนใจสิ่งอื่นระหว่างคำพูด EG:
id="fb-icon"
id="icon-close"
id="large-icon-close"
regex มองหาเครื่องหมายคำพูด"
จากนั้นจะมองหากลุ่มตัวอักษรที่เป็นไปได้ที่ไม่ได้"
จนกว่าจะพบicon
และกลุ่มตัวอักษรใด ๆ ที่เป็นไปได้ที่ไม่ใช่"
มันจะมองหาการปิด"
name="value"
ด้วยname={"value"}
เนื่องจาก regex ของคำตอบนี้ส่งกลับicon
/ value
เป็นกลุ่มที่สอง (ไม่เหมือนกับคำตอบที่ยอมรับ) ค้นหา : =\"([^\"]*?[^\"]*?)\"
แทนที่ :={"$1"}
ฉันชอบเวอร์ชันที่กว้างขึ้นของ Axeman แต่มีปัญหาบางอย่างกับมัน (มันไม่ตรงกับตัวอย่าง
foo "string \\ string" bar
หรือ
foo "string1" bar "string2"
ถูกต้องดังนั้นฉันพยายามที่จะแก้ไข:
# opening quote
(["'])
(
# repeat (non-greedy, so we don't span multiple strings)
(?:
# anything, except not the opening quote, and not
# a backslash, which are handled separately.
(?!\1)[^\\]
|
# consume any double backslash (unnecessary?)
(?:\\\\)*
|
# Allow backslash to escape characters
\\.
)*?
)
# same character as opening quote
\1
string = "\" foo bar\" \"loloo\""
print re.findall(r'"(.*?)"',string)
ลองใช้งานได้ผลเหมือนเป็นเครื่องราง !!!
\
บ่งชี้อักขระข้าม
" foo bar" "loloo"
ขึ้นมา ฉันสงสัยว่าคุณหมายถึงการห่อว่าในสตริงดิบเหมือนที่คุณทำกับ regex r'"\" foo bar\" \"loloo\""'
นี้: โปรดใช้ประโยชน์จากความสามารถในการจัดรูปแบบที่ยอดเยี่ยมของ SO เมื่อใดก็ตามที่เหมาะสม มันไม่ใช่แค่เครื่องสำอาง เราไม่สามารถบอกได้ว่าคุณกำลังพยายามพูดอะไรหากคุณไม่ได้ใช้ และยินดีต้อนรับสู่Stack Overflow !
ต่างจากคำตอบของอดัมฉันมีวิธีง่าย ๆ แต่ใช้ได้:
(["'])(?:\\\1|.)*?\1
และเพิ่มวงเล็บถ้าคุณต้องการรับเนื้อหาในเครื่องหมายคำพูดเช่นนี้:
(["'])((?:\\\1|.)*?)\1
จากนั้น$1
จับคู่อัญประกาศและ$2
จับคู่สตริงเนื้อหา
echo 'junk "Foo Bar" not empty one "" this "but this" and this neither' | sed 's/[^\"]*\"\([^\"]*\)\"[^\"]*/>\1</g'
ซึ่งจะส่งผลให้:> Foo Bar <> <> แต่นี่ <
ที่นี่ฉันแสดงสตริงผลลัพธ์ระหว่าง> <เพื่อความชัดเจนนอกจากนี้ยังใช้เวอร์ชันที่ไม่โลภด้วยคำสั่ง sed นี้ก่อนอื่นเราจะทิ้งขยะก่อนและหลังจากนั้น "" แล้วแทนที่ด้วยส่วนระหว่าง "" และล้อมสิ่งนี้โดย> <ของ
จาก Greg H. ฉันสามารถสร้าง regex นี้ให้เหมาะกับความต้องการของฉัน
ฉันต้องการจับคู่ค่าเฉพาะที่ผ่านการรับรองโดยอยู่ในเครื่องหมายคำพูด ต้องเป็นการจับคู่แบบเต็มไม่มีการจับคู่บางส่วนไม่สามารถเรียกการเข้าชม
เช่น "ทดสอบ" ไม่สามารถจับคู่กับ "test2"
reg = r"""(['"])(%s)\1"""
if re.search(reg%(needle), haystack, re.IGNORECASE):
print "winning..."
ผู้ล่า
หากคุณพยายามค้นหาสตริงที่มีคำต่อท้ายบางตัวเท่านั้นเช่น dot syntax คุณสามารถลองทำสิ่งนี้:
\"([^\"]*?[^\"]*?)\".localized
.localized
คำต่อท้ายอยู่ที่ไหน
ตัวอย่าง:
print("this is something I need to return".localized + "so is this".localized + "but this is not")
มันจะจับ"this is something I need to return".localized
และแต่ไม่"so is this".localized
"but this is not"
คำตอบเพิ่มเติมสำหรับชุดย่อยของตัวแปลงสัญญาณMicrosoft VBAใช้เพียงหนึ่งไลบรารีMicrosoft VBScript Regular Expressions 5.5
และสิ่งนี้จะให้รหัสต่อไปนี้
Sub TestRegularExpression()
Dim oRE As VBScript_RegExp_55.RegExp '* Tools->References: Microsoft VBScript Regular Expressions 5.5
Set oRE = New VBScript_RegExp_55.RegExp
oRE.Pattern = """([^""]*)"""
oRE.Global = True
Dim sTest As String
sTest = """Foo Bar"" ""Another Value"" something else"
Debug.Assert oRE.test(sTest)
Dim oMatchCol As VBScript_RegExp_55.MatchCollection
Set oMatchCol = oRE.Execute(sTest)
Debug.Assert oMatchCol.Count = 2
Dim oMatch As Match
For Each oMatch In oMatchCol
Debug.Print oMatch.SubMatches(0)
Next oMatch
End Sub
สำหรับฉันทำงานอันนี้:
|([\'"])(.*?)\1|i
ฉันใช้ในประโยคแบบนี้:
preg_match_all('|([\'"])(.*?)\1|i', $cont, $matches);
และมันก็ใช้งานได้ดี
คำตอบทั้งหมดข้างต้นนั้นดี .... ยกเว้นพวกเขาจะไม่รองรับตัวอักษรยูนิโค้ดทุกตัว! ที่สคริปต์ ECMA (Javascript)
หากคุณเป็นผู้ใช้ Node คุณอาจต้องการคำตอบที่ยอมรับแล้วซึ่งแก้ไขแล้วซึ่งรองรับอักขระ Unicode ทั้งหมด:
/(?<=((?<=[\s,.:;"']|^)["']))(?:(?=(\\?))\2.)*?(?=\1)/gmu
? The preceding token is not quantifiable