นิพจน์ปกติเพื่อรับสตริงระหว่างสองสตริงใน JavaScript
วิธีการแก้ปัญหาที่สมบูรณ์แบบที่สุดที่จะทำงานในส่วนใหญ่ของกรณีใช้กลุ่มการจับภาพที่มีรูปแบบการจับคู่จุดขี้เกียจ อย่างไรก็ตามจุด.
ใน regex JavaScript ไม่ตรงกับตัวละครแบ่งบรรทัดดังนั้นสิ่งที่จะทำงานในกรณี 100% เป็น[^]
หรือ[\s\S]
/ [\d\D]
/ [\w\W]
โครงสร้าง
ECMAScript 2018 และโซลูชันที่เข้ากันได้ที่ใหม่กว่า
ในสภาพแวดล้อมที่สนับสนุน JavaScript ECMAScript 2018 , s
ปรับปรุงช่วยให้.
เพื่อให้ตรงกับถ่านใด ๆ รวมทั้งตัวอักษรเส้นแบ่งและเครื่องยนต์ regex สนับสนุน lookbehinds ของความยาวตัวแปร ดังนั้นคุณอาจใช้ regex เช่น
var result = s.match(/(?<=cow\s+).*?(?=\s+milk)/gs); // Returns multiple matches if any
// Or
var result = s.match(/(?<=cow\s*).*?(?=\s*milk)/gs); // Same but whitespaces are optional
ในทั้งสองกรณีตำแหน่งปัจจุบันจะถูกตรวจสอบcow
ด้วยการเว้นวรรค 1/0 หรือมากกว่าหลังจากcow
นั้นจะมีการจับคู่และการใช้งาน 0+ ตัวอักษรให้น้อยที่สุดเท่าที่จะเป็นไปได้ (= เพิ่มในค่าการจับคู่) แล้วmilk
ตรวจสอบด้วย 1/0 หรือมากกว่าช่องว่างก่อนหน้าสตริงย่อยนี้)
สถานการณ์ที่ 1: อินพุตบรรทัดเดียว
สถานการณ์นี้และสถานการณ์อื่นทั้งหมดด้านล่างได้รับการสนับสนุนโดยสภาพแวดล้อม JavaScript ทั้งหมด ดูตัวอย่างการใช้งานที่ด้านล่างของคำตอบ
cow (.*?) milk
cow
พบครั้งแรกแล้วพื้นที่นั้น ๆ 0+ ตัวอักษรอื่นที่ไม่ใช่ตัวอักษรเส้นแบ่งน้อยที่สุดเท่าที่*?
เป็นปริมาณขี้เกียจจะถูกจับเข้าไปในกลุ่มที่ 1 และจากนั้นพื้นที่ที่มีmilk
จะต้องปฏิบัติตาม (และผู้ที่จะถูกจับคู่และการบริโภคมากเกินไป )
สถานการณ์ที่ 2: ป้อนข้อมูลแบบหลายบรรทัด
cow ([\s\S]*?) milk
ที่นี่cow
และมีการจับคู่ช่องว่างก่อนจากนั้นจะมีการจับคู่และตัวอักษรใด ๆ น้อยกว่า 0 ตัวที่เป็นไปได้และจับภาพไว้ในกลุ่มที่ 1 จากนั้นmilk
จะจับคู่ช่องว่างด้วย
สถานการณ์ที่ 3: การจับคู่ที่ทับซ้อนกัน
หากคุณมีสายอักขระเหมือนกัน>>>15 text>>>67 text2>>>
และคุณจำเป็นต้องได้รับการจับคู่ 2 ครั้งระหว่าง>>>
+ number
+ whitespace
และ>>>
คุณไม่สามารถใช้งานได้/>>>\d+\s(.*?)>>>/g
เนื่องจากจะพบการแข่งขันเพียง 1 รายการเนื่องจากข้อเท็จจริง>>>
ก่อนหน้า67
นี้จะถูกใช้ไปแล้วเมื่อค้นหาการจับคู่ครั้งแรก คุณสามารถใช้lookahead เชิงบวกเพื่อตรวจสอบว่ามีข้อความอยู่หรือไม่โดย "gobbling" (เช่นต่อท้ายการแข่งขัน):
/>>>\d+\s(.*?)(?=>>>)/g
ดูตัวอย่างผลการทดลอง regex ออนไลน์text1
และtext2
พบเนื้อหาของกลุ่ม 1
ยังเห็นวิธีการที่จะได้รับการแข่งขันที่ทับซ้อนกันเป็นไปได้ทั้งหมดสำหรับสตริง
ข้อควรพิจารณาด้านประสิทธิภาพ
รูปแบบการจับคู่จุดขี้เกียจ ( .*?
) ภายในรูปแบบ regex อาจทำให้การเรียกใช้สคริปต์ช้าลงหากมีการป้อนข้อมูลที่ยาวมาก ในหลายกรณีเทคนิค unroll-the-loopช่วยในระดับที่มากขึ้น พยายามที่จะคว้าทุกอย่างจากcow
และmilk
จาก"Their\ncow\ngives\nmore\nmilk"
เราเห็นว่าเราเพียงแค่ต้องตรงกับทุกบรรทัดที่ไม่ได้เริ่มต้นด้วยmilk
ดังนั้นแทนที่จะใช้cow\n([\s\S]*?)\nmilk
เราสามารถใช้:
/cow\n(.*(?:\n(?!milk$).*)*)\nmilk/gm
ดูตัวอย่างของ regex (ถ้ามีให้\r\n
ใช้/cow\r?\n(.*(?:\r?\n(?!milk$).*)*)\r?\nmilk/gm
) ด้วยชุดทดสอบขนาดเล็กนี้ประสิทธิภาพที่เพิ่มขึ้นนั้นเล็กน้อย แต่ด้วยข้อความที่มีขนาดใหญ่มากคุณจะรู้สึกถึงความแตกต่าง (โดยเฉพาะอย่างยิ่งถ้าเส้นยาว
ตัวอย่างการใช้ regex ใน JavaScript:
//Single/First match expected: use no global modifier and access match[1]
console.log("My cow always gives milk".match(/cow (.*?) milk/)[1]);
// Multiple matches: get multiple matches with a global modifier and
// trim the results if length of leading/trailing delimiters is known
var s = "My cow always gives milk, thier cow also gives milk";
console.log(s.match(/cow (.*?) milk/g).map(function(x) {return x.substr(4,x.length-9);}));
//or use RegExp#exec inside a loop to collect all the Group 1 contents
var result = [], m, rx = /cow (.*?) milk/g;
while ((m=rx.exec(s)) !== null) {
result.push(m[1]);
}
console.log(result);
ใช้String#matchAll
วิธีการที่ทันสมัย
const s = "My cow always gives milk, thier cow also gives milk";
const matches = s.matchAll(/cow (.*?) milk/g);
console.log(Array.from(matches, x => x[1]));