ฉันจะรับสตริงย่อย" It's big \"problem "
โดยใช้นิพจน์ทั่วไปได้อย่างไร
s = ' function(){ return " It\'s big \"problem "; }';
ฉันจะรับสตริงย่อย" It's big \"problem "
โดยใช้นิพจน์ทั่วไปได้อย่างไร
s = ' function(){ return " It\'s big \"problem "; }';
คำตอบ:
/"(?:[^"\\]|\\.)*"/
ทำงานใน The Regex Coach และ PCRE Workbench
ตัวอย่างการทดสอบใน JavaScript:
var s = ' function(){ return " Is big \\"problem\\", \\no? "; }';
var m = s.match(/"(?:[^"\\]|\\.)*"/);
if (m != null)
alert(m);
(?:...)
เป็นกลุ่มแฝงหรือไม่จับภาพ หมายความว่าไม่สามารถอ้างอิงย้อนกลับได้ในภายหลัง
/(["'])(?:[^\1\\]|\\.)*?\1/
var s = ' my \\"new\\" string and \"this should be matched\"';
วิธีนี้จะนำไปสู่ผลลัพธ์ที่ไม่คาดคิด
อันนี้มาจาก nanorc ตัวอย่างที่มีอยู่ใน linux distros จำนวนมาก ใช้สำหรับการเน้นไวยากรณ์ของสตริงสไตล์ C
\"(\\.|[^\"])*\"
var s = ' my \\"new\\" string and \"this should be matched\"';
วิธีนี้จะนำไปสู่ผลลัพธ์ที่ไม่คาดคิด
" \"(\\\\.|[^\\\"])*\" "
ตามที่ ePharaoh ให้ไว้คำตอบคือ
/"([^"\\]*(\\.[^"\\]*)*)"/
หากต้องการให้ข้างต้นใช้กับสตริงที่ยกมาเดี่ยวหรือคู่ที่ยกมาให้ใช้
/"([^"\\]*(\\.[^"\\]*)*)"|\'([^\'\\]*(\\.[^\'\\]*)*)\'/
โซลูชันส่วนใหญ่ที่ให้ไว้ที่นี่ใช้เส้นทางการทำซ้ำทางเลือกเช่น (A | B) *
คุณอาจพบปัญหาสแต็กล้นในอินพุตขนาดใหญ่เนื่องจากคอมไพลเลอร์รูปแบบบางตัวใช้สิ่งนี้โดยใช้การเรียกซ้ำ
Java เช่น: http://bugs.java.com/bugdatabase/view_bug.do?bug_id=6337993
สิ่งนี้:
"(?:[^"\\]*(?:\\.)?)*"
หรือสิ่งที่ Guy Bedford จัดเตรียมไว้จะช่วยลดจำนวนขั้นตอนการแยกวิเคราะห์เพื่อหลีกเลี่ยงการล้นสแต็กส่วนใหญ่
/"(?:[^"\\]++|\\.)*+"/
นำมาจากman perlre
ระบบ Linux ที่ติดตั้ง Perl 5.22.0 โดยตรง ในการเพิ่มประสิทธิภาพ regex นี้ใช้รูปแบบ 'posessive' ของทั้งสอง+
และ*
เพื่อป้องกันการย้อนกลับเนื่องจากเป็นที่ทราบกันดีอยู่แล้วว่าสตริงที่ไม่มีเครื่องหมายคำพูดปิดจะไม่ตรงกันในทุกกรณี
/(["\']).*?(?<!\\)(\\\\)*\1/is
ควรใช้กับสตริงที่ยกมา
สิ่งนี้ทำงานได้อย่างสมบูรณ์แบบบน PCRE และไม่ตกอยู่กับ StackOverflow
"(.*?[^\\])??((\\\\)+)?+"
คำอธิบาย:
"
;.*?
{Lazy match}; ลงท้ายด้วยตัวหนีไม่ใช่[^\\]
;(.*?[^\\])??
"
) แต่ก็สามารถจะนำหน้าด้วยเลขคู่ของคู่สัญญาณหลบหนี(\\\\)+
; และเป็นตัวเลือก Greedy (!): ((\\\\)+)?+
{Greedy matching} สตริง bacause สามารถว่างเปล่าหรือไม่มีคู่ลงท้าย!"(.*?[^\\])?(\\\\)*"
นี่คือสิ่งที่ใช้ได้กับทั้ง "และ" และคุณสามารถเพิ่มรายการอื่น ๆ ได้อย่างง่ายดายเมื่อเริ่มต้น
( "| ') (: \\\ 1 | [^ \ 1])? * \ 1
มันใช้ backreference (\ 1) ตรงกับสิ่งที่อยู่ในกลุ่มแรก ("หรือ ')
[^\1]
ควรแทนที่ด้วย.
เพราะไม่มีสิ่งที่เรียกว่า anti-back-reference และมันก็ไม่สำคัญอะไร เงื่อนไขแรกจะตรงกันเสมอก่อนที่จะมีอะไรเลวร้ายเกิดขึ้น
[^\1]
ด้วย.
จะเปลี่ยน regex นี้เป็นอย่างมีประสิทธิภาพ("|').*?\1
แล้วมันจะตรงกับ"foo\"
ใน"foo \" bar"
. ที่กล่าวว่าการ[^\1]
ไปทำงานจริงเป็นเรื่องยาก @ mathiashansen - คุณดีกับเทอะทะและมีราคาแพง(?!\1).
(ดังนั้น regex ทั้งมีการทำความสะอาดที่มีประสิทธิภาพบางส่วนจะเป็น(["'])(?:\\.|(?!\1).)*+\1
ได้. +
เป็นตัวเลือกถ้าเครื่องยนต์ของคุณไม่สนับสนุน.
ตัวเลือกที่ไม่เคยสัมผัสมาก่อนคือ:
สิ่งนี้มีโบนัสเพิ่มเติมจากความสามารถในการจับคู่แท็กที่ใช้ Escape เปิดได้อย่างถูกต้อง
สมมติว่าคุณมีสตริงต่อไปนี้ String \"this "should" NOT match\" and "this \"should\" match"
ที่นี่\"this "should" NOT match\"
ไม่ควรจับคู่และ"should"
ควรจะเป็น ยิ่งไปกว่านั้นthis \"should\" match
ควรจับคู่และ\"should\"
ไม่ควร
ก่อนอื่นตัวอย่าง
// The input string.
const myString = 'String \\"this "should" NOT match\\" and "this \\"should\\" match"';
// The RegExp.
const regExp = new RegExp(
// Match close
'([\'"])(?!(?:[\\\\]{2})*[\\\\](?![\\\\]))' +
'((?:' +
// Match escaped close quote
'(?:\\1(?=(?:[\\\\]{2})*[\\\\](?![\\\\])))|' +
// Match everything thats not the close quote
'(?:(?!\\1).)' +
'){0,})' +
// Match open
'(\\1)(?!(?:[\\\\]{2})*[\\\\](?![\\\\]))',
'g'
);
// Reverse the matched strings.
matches = myString
// Reverse the string.
.split('').reverse().join('')
// '"hctam "\dluohs"\ siht" dna "\hctam TON "dluohs" siht"\ gnirtS'
// Match the quoted
.match(regExp)
// ['"hctam "\dluohs"\ siht"', '"dluohs"']
// Reverse the matches
.map(x => x.split('').reverse().join(''))
// ['"this \"should\" match"', '"should"']
// Re order the matches
.reverse();
// ['"should"', '"this \"should\" match"']
เอาล่ะตอนนี้เพื่ออธิบาย RegExp นี่คือ regexp สามารถแบ่งออกเป็นสามชิ้นได้อย่างง่ายดาย ดังต่อไปนี้:
# Part 1
(['"]) # Match a closing quotation mark " or '
(?! # As long as it's not followed by
(?:[\\]{2})* # A pair of escape characters
[\\] # and a single escape
(?![\\]) # As long as that's not followed by an escape
)
# Part 2
((?: # Match inside the quotes
(?: # Match option 1:
\1 # Match the closing quote
(?= # As long as it's followed by
(?:\\\\)* # A pair of escape characters
\\ #
(?![\\]) # As long as that's not followed by an escape
) # and a single escape
)| # OR
(?: # Match option 2:
(?!\1). # Any character that isn't the closing quote
)
)*) # Match the group 0 or more times
# Part 3
(\1) # Match an open quotation mark that is the same as the closing one
(?! # As long as it's not followed by
(?:[\\]{2})* # A pair of escape characters
[\\] # and a single escape
(?![\\]) # As long as that's not followed by an escape
)
สิ่งนี้อาจชัดเจนกว่ามากในรูปแบบภาพ: สร้างโดยใช้Regulex ของ Jex
รูปภาพบน github (JavaScript Regular Expression Visualizer) ขออภัยฉันไม่มีชื่อเสียงมากพอที่จะรวมรูปภาพดังนั้นตอนนี้จึงเป็นเพียงลิงก์
นี่คือส่วนสำคัญของฟังก์ชันตัวอย่างที่ใช้แนวคิดนี้ซึ่งเป็นขั้นสูงกว่าเล็กน้อย: https://gist.github.com/scagood/bd99371c072d49a4fee29d193252f5fc#file-matchquotes-js
ต้องจำไว้ว่า regexps ไม่ใช่กระสุนเงินสำหรับสตริง -y ทุกอย่าง บางสิ่งทำได้ง่ายกว่าด้วยเคอร์เซอร์และการค้นหาเชิงเส้นด้วยตนเอง CFLจะทำเคล็ดลับสวยนิด ๆ แต่มีการใช้งานไม่มาก CFL (AFAIK)
https://stackoverflow.com/a/10786066/1794894เวอร์ชันที่ครอบคลุมมากขึ้น
/"([^"\\]{50,}(\\.[^"\\]*)*)"|\'[^\'\\]{50,}(\\.[^\'\\]*)*\'|“[^”\\]{50,}(\\.[^“\\]*)*”/
รุ่นนี้ยังประกอบด้วย
“
และปิด”
)messed รอบที่regexpalและจบลงด้วย regex นี้: (ไม่ต้องถามฉันว่ามันทำงานอย่างไรผมแทบจะไม่เข้าใจแม้สรรพสินค้าฉันเขียนมันฮ่า ๆ )
"(([^"\\]?(\\\\)?)|(\\")+)+"
หากมีการค้นหาตั้งแต่ต้นสิ่งนี้อาจได้ผล?
\"((\\\")|[^\\])*\"
ฉันประสบปัญหาคล้ายกันในการพยายามลบสตริงที่ยกมาซึ่งอาจรบกวนการแยกวิเคราะห์ไฟล์บางไฟล์
ฉันลงเอยด้วยวิธีแก้ปัญหาสองขั้นตอนที่เอาชนะ regex ที่ซับซ้อนใด ๆ ที่คุณสามารถทำได้:
line = line.replace("\\\"","\'"); // Replace escaped quotes with something easier to handle
line = line.replaceAll("\"([^\"]*)\"","\"x\""); // Simple is beautiful
อ่านง่ายกว่าและอาจมีประสิทธิภาพมากขึ้น
หาก IDE ของคุณคือ IntelliJ Idea คุณสามารถลืมอาการปวดหัวเหล่านี้และจัดเก็บ regex ของคุณไว้ในตัวแปร String และเมื่อคุณคัดลอกวางลงในเครื่องหมายคำพูดคู่มันจะเปลี่ยนเป็นรูปแบบ regex ที่ยอมรับได้โดยอัตโนมัติ
ตัวอย่างใน Java:
String s = "\"en_usa\":[^\\,\\}]+";
ตอนนี้คุณสามารถใช้ตัวแปรนี้ใน regexp หรือที่ใดก็ได้