วิธีการใช้ JavaScript regex มากกว่าหลายบรรทัด?


275
var ss= "<pre>aaaa\nbbb\nccc</pre>ddd";
var arr= ss.match( /<pre.*?<\/pre>/gm );
alert(arr);     // null

ฉันต้องการให้บล็อก PRE ถูกหยิบขึ้นมาแม้ว่ามันจะยาวเกินอักขระขึ้นบรรทัดใหม่ ฉันคิดว่าธง 'm' ทำเช่นนั้น ไม่.

พบคำตอบได้ที่นี่ก่อนโพสต์ เมื่อฉันคิดว่าฉันรู้จัก JavaScript (อ่านหนังสือสามเล่มชั่วโมงทำงาน) และไม่มีวิธีแก้ปัญหาที่มีอยู่ใน SO ฉันจะกล้าโพสต์ต่อไป โยนก้อนหินที่นี่

ดังนั้นทางออกคือ:

var ss= "<pre>aaaa\nbbb\nccc</pre>ddd";
var arr= ss.match( /<pre[\s\S]*?<\/pre>/gm );
alert(arr);     // <pre>...</pre> :)

ไม่มีใครมีวิธีที่เป็นความลับน้อยลงหรือไม่

แก้ไข: นี้เป็นที่ซ้ำกัน แต่เพราะมันยากที่จะหากว่าผมผมไม่เอา

มันเสนอ[^]เป็น "จุดหลายจุด" สิ่งที่ฉันยังไม่เข้าใจคือสาเหตุที่[.\n]ไม่ทำงาน เดานี่เป็นส่วนที่น่าเศร้าของ JavaScript ..


29
regex ลับน้อยลงหรือไม่ เป็นไปไม่ได้โดยธรรมชาติ
รูเบนส์ Farias

btw คุณควรอ่าน: "การแยกวิเคราะห์ Html: The Cthulhu Way" codinghorror.com/blog/archives/001311.html
Rubens Farias

1
การเชื่อมโยงเปลี่ยนจากความคิดเห็นก่อนหน้านี้: blog.codinghorror.com/parsing-html-the-cthulhu-way (5yrs-ish ในภายหลัง)
ตบเบา ๆ

คำตอบ:


248

[.\n]ไม่ได้เพราะ.ไม่มีความหมายพิเศษภายในของมันก็หมายถึงตัวอักษร[] จะเป็นวิธีในการระบุ "อักขระใด ๆ รวมถึงการขึ้นบรรทัดใหม่" ถ้าคุณต้องการเพื่อให้ตรงกับการขึ้นบรรทัดใหม่ที่ทุกท่านจะต้องเพิ่มเป็นอย่างดีที่จะรวมถึง Windows และ Mac OS คลาสสิกตอนจบบรรทัดรูปแบบ:.(.|\n)\r(.|[\r\n])

ที่ดูค่อนข้างยุ่งยากและช้า (ดูคำตอบของ KrisWebDev สำหรับรายละเอียด ) ดังนั้นวิธีที่ดีกว่าคือการจับคู่อักขระช่องว่างทั้งหมดและอักขระที่ไม่ใช่ช่องว่างทั้งหมดด้วย[\s\S]ซึ่งจะจับคู่ทุกอย่างและเร็วขึ้นและ ที่เรียบง่าย

โดยทั่วไปคุณไม่ควรลองใช้ regexp เพื่อจับคู่แท็ก HTML จริง ตัวอย่างเช่นดูคำถามเหล่านี้ สำหรับข้อมูลเพิ่มเติมเกี่ยวกับสาเหตุ

ให้ลองค้นหาแท็กที่คุณต้องการจริง ๆ (ใช้ jQuery ทำให้มันง่ายขึ้น แต่คุณสามารถทำได้document.getElementsByTagName("pre")กับ DOM มาตรฐานเสมอ) จากนั้นค้นหาเนื้อหาข้อความของผลลัพธ์เหล่านั้นด้วย regexp หากคุณต้องการจับคู่กับเนื้อหา .


สิ่งที่ฉันทำคือการทำ. wiki -> การแปลง HTML ได้อย่างรวดเร็วโดยใช้ JavaScript ดังนั้นฉันยังไม่มี DOM พร้อมใช้งาน ไฟล์ Wiki ส่วนใหญ่เป็นไวยากรณ์ของตัวเอง แต่ฉันอนุญาตให้ใช้แท็ก HTML หากจำเป็น คำแนะนำของคุณเป็นอย่างมากที่ถูกต้องถ้าผมซื้อขายใน DOM กับเรื่องนี้ ขอบคุณ :)
akauppi

ยุติธรรมพอสมควร ฉันคิดว่านั่นเป็นเหตุผลที่ถูกต้องที่จะต้องการใช้ regexes บน HTML แม้ว่าไวยากรณ์ของ wiki ที่ผสมกับ HTML นั้นสามารถสร้างกรณีมุมสนุกได้ทุกชนิดด้วยตนเอง
Brian Campbell

2
[\r\n]ใช้กับลำดับ \ r \ n จะจับคู่ \ r ก่อนแล้วจึง \ n หากคุณต้องการจับคู่ลำดับทั้งหมดในครั้งเดียวโดยไม่คำนึงว่าลำดับนั้นเป็น \ r \ n หรือเพียงแค่ \ n ให้ใช้รูปแบบ.|\r?\n
Eirik Birkeland

1
เพื่อให้ตรงกับทั้ง[\s\S]+สตริงหลายลองโลภ
Boaz

ผมแค่อยากจะเพิ่มสำหรับลูกหลานที่ JS regex ไวยากรณ์ไม่สนใจความหมายของ.ภายใน[]เป็นที่แตกต่างกันกว่ากรอบ regex อื่น ๆ โดยเฉพาะหนึ่งขั้นสูงในการ .NET คนโปรดอย่าคิดว่า regexes เป็นแพลตฟอร์มข้ามพวกเขามักจะไม่ !!
Mr. TA

330

อย่าใช้(.|[\r\n])แทน.การจับคู่แบบหลายบรรทัด

ใช้[\s\S]แทน.การจับคู่แบบหลายบรรทัด

นอกจากนี้หลีกเลี่ยงความโลภที่ไม่จำเป็นต้องโดยใช้*?หรือ+?ปริมาณแทนหรือ* +สิ่งนี้มีผลกระทบต่อประสิทธิภาพอย่างมาก

ดูเกณฑ์มาตรฐานที่ฉันได้ทำ: http://jsperf.com/javascript-multiline-regexp-workarounds

Using [^]: fastest
Using [\s\S]: 0.83% slower
Using (.|\r|\n): 96% slower
Using (.|[\r\n]): 96% slower

NB: คุณยังสามารถใช้[^]แต่มันเลิกใช้ในความคิดเห็นด้านล่าง


22
จุดที่ดี แต่ฉันแนะนำให้ใช้[^]ต่อไป ในอีกด้านหนึ่ง JavaScript เป็นรสชาติเดียวที่ฉันรู้ว่าสนับสนุนสำนวนนั้นและแม้จะมีการใช้บ่อยเท่าที่เคยมี[\s\S]มา ในทางกลับกันรสชาติอื่น ๆ ส่วนใหญ่ให้คุณหลีกเลี่ยง]โดยการระบุไว้ก่อน ในคำอื่น ๆ ใน JavaScript [^][^]ตรงกับตัวละครทั้งสอง แต่ใน .NET มันตรงกับหนึ่งในตัวละครอื่น ๆ กว่า], หรือ[ ^
Alan Moore

1
คุณจะรู้ได้อย่างไรว่า\Sจะจับคู่\rหรือ\nเทียบกับตัวละครอื่น ๆ
Gili

3
ดูคำถามนี้สำหรับรายละเอียด \ s \ S นี่คือแฮ็คที่จะจับคู่อักขระช่องว่างทั้งหมดและอักขระที่ไม่ใช่ช่องว่างทั้งหมด = อักขระทั้งหมด ดูMDNสำหรับเอกสารอักขระพิเศษ regexp
KrisWebDev

4
เหตุผลใดที่จะชอบ[\s\S]มากกว่าคนอื่นเช่น[\d\D]หรือ[\w\W]?
Phrogz

1
ผมขอชี้ให้เห็นอย่างรวดเร็วว่าการทดสอบของคุณสำหรับผู้ดำเนินการโลภนั้น ไม่ตรงกับเนื้อหาเดียวกับ/<p>Can[^]*?<\/p>/ /<p>Can[^]*<\/p>/ควรเปลี่ยนตัวแปรโลภเป็นเพื่อ/<p>(?:[^<]|<(?!\/p>))*<\/p>/ให้ตรงกับเนื้อหาเดียวกัน
3limin4t0r

19

คุณไม่ได้ระบุสภาพแวดล้อมและรุ่นของ Javascript (ECMAscript) ของคุณและฉันรู้ว่าโพสต์นี้มาจากปี 2009 แต่เพียงเพื่อความสมบูรณ์ด้วยการเปิดตัว ECMA2018 เราสามารถใช้การsตั้งค่าสถานะเพื่อให้.ตรงกับ '\ n' ดูhttps : //stackoverflow.com/a/36006948/141801

ดังนั้น:

let s = 'I am a string\nover several\nlines.';
console.log('String: "' + s + '".');

let r = /string.*several.*lines/s; // Note 's' modifier
console.log('Match? ' + r.test(s); // 'test' returns true

นี่เป็นการเพิ่มเมื่อเร็ว ๆ นี้และจะไม่ทำงานในสภาพแวดล้อมปัจจุบันเช่น Node v8.7.0 ดูเหมือนจะไม่รู้จัก แต่ใช้งานได้ใน Chromium และฉันใช้ในการทดสอบ typescript ฉันเขียนและสันนิษฐานว่ามัน จะกลายเป็นกระแสหลักมากขึ้นเมื่อเวลาผ่านไป


1
นี้ทำงานได้ดีใน Chrome (v67) แต่อย่างสมบูรณ์แบ่ง regex (ยังหยุดบรรทัดโดยบรรทัดทำงาน) ใน IE11 และ iEdge (V42)
freedomn-M

ขอบคุณ @ freedomn-m .. IE ไม่รองรับคุณสมบัติใหม่ที่ไม่น่าแปลกใจเกือบสมบูรณ์ :) แต่ใช่มันเป็นมูลค่าการกล่าวถึงที่มันไม่ทำงานเพื่อบันทึกทุกคนพยายาม 'debug' ทำไมพวกเขาพยายามที่จะใช้มันไม่ทำงาน อย่างที่คาดไว้.
Neek

11

[.\n]ใช้งานไม่ได้เพราะ dot in [](ตามคำนิยาม regex ไม่ใช่ javascript เท่านั้น) หมายถึง dot-character คุณสามารถใช้(.|\n)(หรือ(.|[\n\r])) แทน


24
[\s\S]เป็นสำนวน JavaScript ที่ใช้กันมากที่สุดสำหรับการจับคู่ทุกอย่างรวมถึงการขึ้นบรรทัดใหม่ (.|\n)มันเป็นเรื่องง่ายในสายตาและมีประสิทธิภาพมากขึ้นกว่าวิธีการที่สลับกันตามชอบ (มันหมายถึงตัวอักษร "ตัวละครที่เป็นช่องว่างหรือตัวละครที่ไม่ได้เป็นช่องว่าง)
อลันมัวร์

2
คุณถูก แต่คำถามเกี่ยวกับ.และ\nและทำไม[.\n]ไม่ทำงาน ดังที่ได้กล่าวไว้ในคำถาม[^]ก็เป็นแนวทางที่ดีเช่นกัน
Y. Shoham

6

ฉันได้ทำการทดสอบ (Chrome) และมันใช้งานได้สำหรับฉัน (ทั้งคู่[^]และ[^\0]) โดยการเปลี่ยนจุด ( .) โดยอย่างใดอย่างหนึ่ง[^\0]หรือ[^]เพราะจุดไม่ตรงกับตัวแบ่งบรรทัด (ดูที่นี่:http://www.regular-expressions.info/dot.html )

var ss= "<pre>aaaa\nbbb\nccc</pre>ddd";
var arr= ss.match( /<pre[^\0]*?<\/pre>/gm );
alert(arr);     //Working


1
ปัญหา[^\0]คือว่ามันจะไม่ตรงกับตัวละครโมฆะแม้ว่าตัวละครโมฆะได้รับอนุญาตในสตริง Javascript (ดูคำตอบนี้ )
โดนัลด์ดั๊

0

นอกเหนือจากตัวอย่างที่กล่าวข้างต้นมันเป็นทางเลือก

^[\\w\\s]*$

อยู่ที่ไหน\wสำหรับคำและ\sสำหรับช่องว่างสีขาว

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