Làm cách nào để sử dụng regex JavaScript trên nhiều dòng?


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

Tôi muốn khối PRE được chọn, mặc dù nó trải dài trên các ký tự dòng mới. Tôi nghĩ cờ 'm' làm điều đó. Không làm.

Tìm thấy câu trả lời ở đây trước khi đăng. SInce Tôi nghĩ rằng tôi biết JavaScript (đọc ba cuốn sách, giờ làm việc) và không có giải pháp nào hiện có tại SO, tôi sẽ dám đăng mọi cách. ném đá vào đây

Vì vậy, giải pháp là:

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

Có ai có một cách khó hiểu hơn?

Chỉnh sửa: đây là một bản sao nhưng vì nó khó tìm hơn của tôi, tôi không xóa.

Nó đề xuất [^]như một "chấm đa dòng". Điều tôi vẫn không hiểu là tại sao [.\n]nó không hoạt động. Đoán đây là một trong những phần đáng buồn của JavaScript ..


29
Một regex ít khó hiểu hơn? Không thể, bởi bản chất.
Rubens Farias

btw, bạn nên đọc: "Phân tích cú pháp Html: Con đường Cthulhu" mã hóa kinh dị.com / blog / archives / 001311.html
Rubens Farias

1
Liên kết đã thay đổi từ nhận xét trước: blog.codinghorror.com/parsing-html-the-cthulhu-way (5yrs-ish sau)
dab

Câu trả lời:


247

[.\n]không hoạt động vì .không có ý nghĩa đặc biệt bên trong [], nó chỉ có nghĩa là một nghĩa đen .. (.|\n)sẽ là một cách để chỉ định "bất kỳ ký tự nào, bao gồm cả một dòng mới". Nếu bạn muốn khớp tất cả các dòng mới, bạn cũng cần phải thêm \rvào để bao gồm các kết thúc dòng kiểu Mac OS cổ điển : (.|[\r\n]).

Điều đó có vẻ hơi cồng kềnh, cũng như chậm chạp (xem câu trả lời của KrisWebDev để biết chi tiết ), vì vậy cách tiếp cận tốt hơn là khớp tất cả các ký tự khoảng trắng và tất cả các ký tự không phải khoảng trắng [\s\S], sẽ khớp với mọi thứ, và nhanh hơn và đơn giản hơn.

Nói chung, bạn không nên cố gắng sử dụng biểu thức chính quy để khớp với các thẻ HTML thực tế. Xem, ví dụ, những câu hỏi này để biết thêm thông tin về lý do tại sao.

Thay vào đó, hãy thử thực sự tìm kiếm DOM cho thẻ bạn cần (sử dụng jQuery giúp việc này dễ dàng hơn, nhưng bạn luôn có thể thực hiện document.getElementsByTagName("pre")với DOM tiêu chuẩn), sau đó tìm kiếm nội dung văn bản của các kết quả đó với regrec nếu bạn cần đối sánh với nội dung .


Những gì tôi đang làm là thực hiện .wiki -> chuyển đổi HTML nhanh chóng, sử dụng JavaScript. Do đó, tôi chưa có sẵn DOM. Tệp Wiki chủ yếu là cú pháp riêng của nó, nhưng tôi cho phép các thẻ HTML được sử dụng nếu cần. Lời khuyên của bạn là rất hợp lệ, nếu tôi đang kinh doanh DOM với điều này. Cảm ơn. :)
akauppi

Đủ công bằng. Tôi cho rằng đó là một lý do hợp lệ để muốn sử dụng regexes trên HTML, mặc dù các cú pháp wiki trộn với HTML có thể có tất cả các loại trường hợp góc thú vị.
Brian Campbell

2
[\r\n]áp dụng cho chuỗi \ r \ n, trước tiên sẽ khớp với \ r và sau đó \ n. Nếu bạn muốn khớp toàn bộ chuỗi cùng một lúc, bất kể chuỗi đó là \ r \ n hay chỉ là \ n, hãy sử dụng mẫu.|\r?\n
Eirik Birkeland

1
Để phù hợp với toàn bộ chuỗi đa dòng, hãy thử tham lam [\s\S]+.
Boaz

Tôi chỉ muốn thêm cho hậu thế rằng JS regex cú pháp bỏ qua ý nghĩa của .bên []khác nhau hơn so với các khuôn khổ regex khác, đặc biệt là một tiên tiến trong .NET. Mọi người, xin đừng cho rằng regex là nền tảng chéo, họ thường không !!
Ông TA

330

KHÔNG sử dụng (.|[\r\n])thay vì .kết hợp nhiều dòng.

NÊN sử dụng [\s\S]thay vì .kết hợp nhiều dòng

Ngoài ra, tránh tham lam khi không cần thiết bằng cách sử dụng *?hoặc +?định lượng thay vì *hoặc +. Điều này có thể có một tác động hiệu suất rất lớn.

Xem điểm chuẩn tôi đã thực hiện: http://jsperf.com/javascript-multiline-regapi-workaround

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

NB: Bạn cũng có thể sử dụng [^]nhưng nó không được dùng trong bình luận bên dưới.


22
Điểm tốt, nhưng tôi khuyên bạn không nên sử dụng [^]anyway. Một mặt, JavaScript là hương vị duy nhất tôi biết hỗ trợ cho thành ngữ đó và thậm chí ở đó nó không được sử dụng ở đâu thường xuyên như vậy [\s\S]. Mặt khác, hầu hết các hương vị khác cho phép bạn thoát khỏi ]bằng cách liệt kê nó đầu tiên. Nói cách khác, trong JavaScript [^][^]khớp với bất kỳ hai nhân vật, nhưng trong .NET nó phù hợp với bất kỳ một nhân vật khác hơn ], [hoặc ^.
Alan Moore

1
Làm thế nào để bạn biết rằng \Ssẽ phù hợp \rhoặc \nso với một số nhân vật khác?
Gili

3
Xem câu hỏi này để biết chi tiết \ s \ S. Đây là một hack để phù hợp với tất cả các ký tự khoảng trắng + tất cả các ký tự không phải khoảng trắng = tất cả các ký tự. Xem thêm MDN để biết tài liệu ký tự đặc biệt regrec.
KrisWebDev

4
Bất kỳ lý do để thích [\s\S]hơn người khác, thích [\d\D]hay [\w\W]?
Phrogz

1
Hãy để tôi nhanh chóng chỉ ra rằng thử nghiệm của bạn cho toán tử tham lam là gian lận. /<p>Can[^]*?<\/p>/không phù hợp với nội dung tương tự như /<p>Can[^]*<\/p>/. Các biến thể tham lam nên được thay đổi /<p>(?:[^<]|<(?!\/p>))*<\/p>/để phù hợp với cùng một nội dung.
3limin4t0r

19

Bạn không chỉ định môi trường và phiên bản Javascript (ECMAscript) của mình và tôi nhận ra bài đăng này là từ năm 2009, nhưng để hoàn thiện, với việc phát hành ECMA2018, giờ đây chúng ta có thể sử dụng scờ để tạo ra .để khớp với '\ n', xem https : //stackoverflow.com/a/36006948/141801

Như vậy:

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

Đây là một bổ sung gần đây và sẽ không hoạt động trong nhiều môi trường hiện tại, ví dụ Node v8.7.0 dường như không nhận ra nó, nhưng nó hoạt động trong Chromium và tôi đang sử dụng nó trong một bài kiểm tra Bản mô tả tôi đang viết và có lẽ là nó sẽ trở nên chủ đạo hơn khi thời gian trôi qua.


1
Điều này hoạt động rất tốt trong Chrome (v67) nhưng phá vỡ hoàn toàn regex (cũng dừng hoạt động từng dòng một) trong IE11 và IEdge (v42)
Freedomn-m

Cảm ơn @ Freedomn-m .. IE không hỗ trợ một tính năng rất mới gần như hoàn toàn không gây ngạc nhiên :) Nhưng vâng, đáng nói là nó không hoạt động để cứu bất cứ ai cố gắng 'gỡ lỗi' tại sao nỗ lực sử dụng của nó không hoạt động như mong đợi.
Neek

11

[.\n]không hoạt động, bởi vì dấu chấm trong [](theo định nghĩa regex; không chỉ javascript) có nghĩa là ký tự dấu chấm. Bạn có thể sử dụng (.|\n)(hoặc (.|[\n\r])) thay thế.


24
[\s\S]là thành ngữ JavaScript phổ biến nhất để khớp mọi thứ, kể cả dòng mới. Nó dễ nhìn hơn và hiệu quả hơn nhiều so với cách tiếp cận dựa trên xen kẽ như (.|\n). (Nghĩa đen là "bất kỳ ký tự nào khoảng trắng hoặc bất kỳ ký tự nào không phải là khoảng trắng.)
Alan Moore

2
Bạn nói đúng, nhưng câu hỏi là về .\n, và tại sao [.\n]không làm việc. Như đã đề cập trong câu hỏi, [^]cách tiếp cận cũng tốt đẹp.
Y. Shoham

6

Tôi đã thử nghiệm nó (Chrome) và nó làm việc cho tôi (cả [^][^\0]), bằng cách thay đổi các dấu chấm ( .) bằng một trong hai [^\0]hoặc [^], bởi vì dấu chấm không phù hợp ngắt dòng (Xem ở đây:http://www.uity-expressions.info/dot.html ).

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


1
Vấn đề với [^\0]là nó sẽ không khớp với các ký tự null mặc dù các ký tự null được phép trong các chuỗi Javascript (xem câu trả lời này ).
Vịt Donald

0

Ngoài các ví dụ trên, nó là một thay thế.

^[\\w\\s]*$

Nơi \wdành cho từ và \sdành cho khoảng trắng

Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.