Bạn có thể cung cấp một số ví dụ về lý do tại sao khó phân tích cú pháp XML và HTML bằng biểu thức chính quy không? [đóng cửa]


402

Một sai lầm tôi thấy mọi người làm theolặp lại đang cố gắng phân tích cú pháp XML hay HTML với một regex. Dưới đây là một số lý do phân tích cú pháp XML và HTML là khó:

Mọi người muốn coi một tệp là một chuỗi các dòng, nhưng điều này là hợp lệ:

<tag
attr="5"
/>

Mọi người muốn coi thẻ <hoặc <là bắt đầu của thẻ, nhưng những thứ như thế này tồn tại trong tự nhiên:

<img src="imgtag.gif" alt="<img>" />

Mọi người thường muốn khớp các thẻ bắt đầu với các thẻ kết thúc, nhưng XML và HTML cho phép các thẻ chứa chính chúng (điều mà các biểu thức truyền thống không thể xử lý được):

<span id="outer"><span id="inner">foo</span></span> 

Mọi người thường muốn đối chiếu với nội dung của tài liệu (chẳng hạn như vấn đề "tìm tất cả số điện thoại trên một trang nhất định" nổi tiếng), nhưng dữ liệu có thể được đánh dấu (ngay cả khi nó có vẻ bình thường khi xem):

<span class="phonenum">(<span class="area code">703</span>)
<span class="prefix">348</span>-<span class="linenum">3020</span></span>

Nhận xét có thể chứa các thẻ được định dạng kém hoặc không đầy đủ:

<a href="foo">foo</a>
<!-- FIXME:
    <a href="
-->
<a href="bar">bar</a>

Những gì gotchas khác bạn biết?


14
Các trình duyệt web có ý nghĩa về loại lộn xộn này hàng triệu lần một giây, ai đó có thể tạo một lớp trình phân tích cú pháp trang web cho chúng ta không?
Jon Winstanley

24
Jon, họ có. Trong Perl có nhiều HTML :: Parser, HTML :: TreeBuilder, v.v ... Gần như chắc chắn có một ngôn ngữ cho ngôn ngữ của bạn.
Chas. Owens

12
Câu trả lời tốt nhất là, stackoverflow.com/a/1732454/135078 (Cẩn thận Zalgo)
Kelly S. Pháp

3
Có một lời giải thích tốt tại sao [bạn không thể phân tích [X] HTML bằng regex] [1] [1]: stackoverflow.com/a/1732454/468725
Pavel P

4
Đây là một lời giải thích tốt về cách bạn chắc chắn có thể phân tích HTML bằng các mẫu , cũng như lý do tại sao bạn có thể không muốn làm như vậy.
tchrist

Câu trả lời:


260

Đây là một số XML hợp lệ thú vị dành cho bạn:

<!DOCTYPE x [ <!ENTITY y "a]>b"> ]>
<x>
    <a b="&y;>" />
    <![CDATA[[a>b <a>b <a]]>
    <?x <a> <!-- <b> ?> c --> d
</x>

Và gói niềm vui nhỏ này là HTML hợp lệ:

<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd" [
    <!ENTITY % e "href='hello'">
    <!ENTITY e "<a %e;>">
]>
    <title>x</TITLE>
</head>
    <p id  =  a:b center>
    <span / hello </span>
    &amp<br left>
    <!---- >t<!---> < -->
    &e link </a>
</body>

Không đề cập đến tất cả các phân tích cụ thể của trình duyệt cho các cấu trúc không hợp lệ.

Chúc may mắn rỗ regex chống lại điều đó!

EDIT (Jörg W Mittag): Đây là một đoạn hay khác của HTML hợp lệ 4.01:

<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01//EN"
  "http://www.w3.org/TR/html4/strict.dtd"> 
<HTML/
  <HEAD/
    <TITLE/>/
    <P/>

6
Cái XML nào? Có một vài cấu trúc khác nhau ở đó, có rắc rối không? Tập hợp con nội bộ DTD? Đó là xác định một & thực thể mới; được gọi là 'y', chứa chuỗi ']>' thông thường, nếu không có trong ngoặc kép, kết thúc tập hợp con bên trong.
bobince

16
(Điều này chứng tỏ rằng bạn phải có kiến ​​thức khá sâu về một số tính năng DTD bí truyền và cổ xưa hơn của XML để phân tích tài liệu đúng cách, ngay cả khi bạn không phải là trình phân tích cú pháp xác thực DTD.)
bobince

17
Các ví dụ HTML sử dụng một tính năng hiếm khi được biết đến: shorttags. Đọc thêm tại w3.org/QA/2007/10/shorttags.html
netvope

25
Mỗi khi ai đó viết HTML như hình trên, Tim Berners-Lee đều rơi một giọt nước mắt.
fgysin phục hồi Monica

5
Tôi thích cách công cụ đánh dấu cú pháp của Stackoverflow thất bại trong lần xuất hiện đầu tiên của "]".
GlassGhost

71

Thực ra

<img src="imgtag.gif" alt="<img>" />

HTML không hợp lệ và cũng không phải là XML hợp lệ.

Nó không phải là XML hợp lệ vì '<' và '>' không phải là các ký tự hợp lệ bên trong các chuỗi thuộc tính. Chúng cần được thoát bằng cách sử dụng các thực thể XML tương ứng & lt; và & gt;

Nó cũng không phải là HTML hợp lệ vì hình thức đóng ngắn không được phép trong HTML (nhưng chính xác trong XML và XHTML). Thẻ 'img' cũng là một thẻ được đóng hoàn toàn theo thông số kỹ thuật HTML 4.01. Điều này có nghĩa là việc đóng thủ công nó thực sự sai và tương đương với việc đóng bất kỳ thẻ nào khác hai lần.

Phiên bản chính xác trong HTML là

<img src="imgtag.gif" alt="&lt;img&gt;">

và phiên bản chính xác trong XHTML và XML là

<img src="imgtag.gif" alt="&lt;img&gt;"/>

Ví dụ sau bạn đưa ra cũng không hợp lệ

<
tag
attr="5"
/>

Đây cũng không phải là HTML hoặc XML hợp lệ. Tên của thẻ phải ở ngay sau '<', mặc dù các thuộc tính và đóng '>' có thể là bất cứ nơi nào chúng muốn. Vì vậy, XML hợp lệ thực sự là

<tag
attr="5"
/>

Và đây là một trò vui khác: bạn thực sự có thể chọn sử dụng "hoặc" làm ký tự trích dẫn thuộc tính của mình

<img src="image.gif" alt='This is single quoted AND valid!'>

Tất cả các lý do khác đã được đăng là chính xác, nhưng vấn đề lớn nhất với phân tích cú pháp HTML là mọi người thường không hiểu chính xác tất cả các quy tắc cú pháp. Việc trình duyệt của bạn diễn giải các thẻ của bạn dưới dạng HTML không có nghĩa là bạn đã thực sự viết HTML hợp lệ.

Chỉnh sửa: Và thậm chí stackoverflow.com đồng ý với tôi về định nghĩa hợp lệ và không hợp lệ. XML / HTML không hợp lệ của bạn không được tô sáng, trong khi phiên bản đã sửa của tôi là.

Về cơ bản, XML không được phân tích cú pháp bằng biểu thức chính quy. Nhưng cũng không có lý do để làm như vậy. Có rất nhiều, rất nhiều trình phân tích cú pháp XML cho mỗi và mọi ngôn ngữ. Bạn có thể lựa chọn giữa trình phân tích cú pháp SAX, trình phân tích cú pháp DOM và trình phân tích cú pháp Pull. Tất cả những thứ này được đảm bảo sẽ nhanh hơn nhiều so với phân tích cú pháp với regrec và sau đó bạn có thể sử dụng các công nghệ tuyệt vời như XPath hoặc XSLT trên cây DOM kết quả.

Do đó, câu trả lời của tôi là: không chỉ phân tích cú pháp XML với regexps khó mà còn là một ý tưởng tồi. Chỉ cần sử dụng một trong hàng triệu trình phân tích cú pháp XML hiện có và tận dụng tất cả các tính năng nâng cao của XML.

HTML quá khó để tự mình phân tích cú pháp. Đầu tiên, cú pháp pháp lý có nhiều điểm tinh tế nhỏ mà bạn có thể không biết và thứ hai, HTML trong tự nhiên chỉ là một đống hôi thối khổng lồ (bạn hiểu ý tôi). Có một loạt các thư viện phân tích cú pháp lỏng lẻo làm tốt công việc xử lý HTML như súp thẻ, chỉ cần sử dụng các thư viện này.


8
Bạn không cần phải thoát> như> mặc dù.
Joey

8
Được rồi, s / hợp lệ / tồn tại trong tự nhiên / g
Chas. Owens

1
Trên thực tế, theo đặc điểm kỹ thuật bạn phải thoát> như> giống như bạn phải thoát <như <& và & amp; và trong các thuộc tính "như & quot; và 'như & apos; chỉ có nhiều trình phân tích cú pháp
LordOfThePigs

19
Thông số kỹ thuật không nói '>' phải được thoát - ngoại trừ trường hợp đặc biệt của chuỗi ']]>' trong nội dung. Vì lý do này, dễ nhất là luôn thoát '>', nhưng nó không bắt buộc bởi spec.
bobince

8
>dấu hiệu này là hoàn toàn hợp lệ trong html stackoverflow.com/questions/94528/ trên
jfs

56

Tôi đã viết toàn bộ một mục blog về chủ đề này: Hạn chế biểu hiện thông thường

Mấu chốt của vấn đề là HTML và XML là các cấu trúc đệ quy yêu cầu các cơ chế đếm để phân tích chính xác. Một regex thực sự không có khả năng đếm. Bạn phải có một ngữ pháp miễn phí ngữ cảnh để tính.

Đoạn trước đi kèm với một cảnh báo nhẹ. Một số triển khai regex hiện hỗ trợ cho ý tưởng đệ quy. Tuy nhiên, một khi bạn bắt đầu thêm đệ quy vào biểu thức regex của mình, bạn thực sự kéo dài ranh giới và nên xem xét một trình phân tích cú pháp.


20

Một điều không có trong danh sách của bạn là các thuộc tính có thể xuất hiện theo bất kỳ thứ tự nào, vì vậy nếu regex của bạn đang tìm kiếm một liên kết với href "foo" và "thanh" lớp, chúng có thể đến theo bất kỳ thứ tự nào và có bất kỳ số lượng nào khác những thứ giữa họ.


À, vâng, đó thậm chí là câu hỏi khiến tôi phải hỏi câu này (liên kết đầu tiên).
Chas. Owens

16

Nó phụ thuộc vào những gì bạn có nghĩa là "phân tích cú pháp". Nói chung, XML không thể được phân tích cú pháp bằng regex vì ngữ pháp XML không có nghĩa là thông thường. Nói một cách đơn giản, regexes không thể đếm (tốt, các regex Perl thực sự có thể đếm được mọi thứ) vì vậy bạn không thể cân bằng các thẻ đóng mở.


tôi đoán phản hồi có thể giải quyết vấn đề về thẻ mở và đóng
Rishul Matta

1
@RishulMatta: thế nào? Bạn chỉ có một số lượng hạn chế phản hồi và lưu ý rằng bạn cần đảo ngược các thẻ ... Ngoài ra, định nghĩa chặt chẽ về biểu thức chính quy không cho phép phản hồi.
Willem Van Onsem

.NET cho phép cân bằng các biểu thức, bật và đẩy, và về mặt lý thuyết có thể được sử dụng để phù hợp với hệ thống phân cấp. Nhưng đó vẫn là một ý tưởng tồi.
Abel

9

Có phải mọi người đang thực sự mắc lỗi bằng cách sử dụng biểu thức chính quy, hoặc đơn giản là nó đủ tốt cho nhiệm vụ mà họ đang cố gắng đạt được?

Tôi hoàn toàn đồng ý rằng phân tích cú pháp html và xml bằng regex là không thể như những người khác đã trả lời.

Tuy nhiên, nếu yêu cầu của bạn không phải là phân tích cú pháp html / xml mà chỉ cần lấy một chút dữ liệu trong một bit html / xml "đã biết" thì có thể là một biểu thức chính quy hoặc thậm chí là một "chuỗi con" đơn giản hơn thậm chí là đủ.


7
Xác định "đủ tốt". Chắc chắn regex đơn giản sẽ không hoạt động. Không phù hợp với một cái gì đó hoặc phù hợp với một cái gì đó bạn không nên là một lỗi? Nếu vậy thì sử dụng regexes là một sai lầm. Các trình phân tích cú pháp HTML và XML không khó sử dụng. Tránh học chúng là một nền kinh tế sai lầm.
Chas. Owens

1
ok, định nghĩa "đủ tốt". Hãy nói rằng tôi có một trang web cho tôi biết địa chỉ IP của khách hàng. Đó là tất cả những gì nó làm. Bây giờ, tôi cần phải viết một ứng dụng cho máy khách cho tôi biết địa chỉ IP của nó. Tôi vào trang web đó, tìm địa chỉ IP và trả lại. Phân tích cú pháp HTML là không cần thiết!
Ngày Robin

2
Nếu bạn có một chuỗi tùy ý có định dạng hoàn toàn nằm dưới sự kiểm soát của bạn, thì thực tế là chuỗi đó được tạo thành XML thực sự không liên quan. Nhưng hầu như không có trường hợp sử dụng nào cho XML thực sự thuộc loại này.
Robert Rossney

15
Tôi có thể nói với bạn từ kinh nghiệm đau đớn rằng hầu hết thời gian có thể có được những gì bạn muốn bằng cách sử dụng các mẫu biểu thức phức tạp vô lý. Cho đến khi trang web trải qua một thay đổi nhỏ vui nhộn và bạn có thể ném regex này khiến bạn khóc trong hai ngày ra khỏi cửa sổ và bắt đầu lại.
Thomasz

@Robert: "hầu như không có trường hợp sử dụng" là một cường điệu. Theo kinh nghiệm của tôi, có những trường hợp sử dụng đủ phổ biến. YAGNI áp dụng ở đây ... đôi khi. Bí quyết là biết giải pháp chống đạn và tồn tại lâu dài của bạn như thế nào, cho nhiệm vụ cụ thể mà bạn đang giải quyết. Robin có một điểm tốt. Ông chỉ nói rằng phân tích cú pháp XML đầy đủ không phải lúc nào cũng có giá trị ... điều đó đúng ngay cả khi bạn biết cách sử dụng nó.
LarsH

6

Mọi người thường mặc định viết các mẫu tham lam, thường đủ dẫn đến việc không suy nghĩ thấu đáo. * Đưa các khối tệp lớn vào <foo> lớn nhất có thể. * </ Foo>.


2
Cũng như làm cho sự lặp lại lười biếng với .*?<, bạn có thể khắc phục điều đó bằng cách sử dụng một lớp ký tự phủ định như thế nào [^<]*<. (Tuyên bố miễn trừ trách nhiệm: rõ ràng điều đó vẫn không thể đánh lừa được, đó là điểm của câu hỏi.)
Rory O'Kane

6

Tôi muốn nói "đừng tái tạo bánh xe". Ngoại trừ XML là một thực sự, thực sự định dạng phức tạp. Vì vậy, có lẽ tôi nên nói "đừng phát minh lại synchrotron."

Có lẽ sáo ngữ chính xác bắt đầu "khi tất cả những gì bạn có là một cái búa ..." Bạn biết cách sử dụng các biểu thức chính quy, biểu thức chính quy rất tốt trong việc phân tích cú pháp, vậy tại sao phải học một thư viện phân tích cú pháp XML?

Bởi vì phân tích cú pháp XML là khó . Bất kỳ nỗ lực nào bạn tiết kiệm được bằng cách không phải học cách sử dụng thư viện phân tích cú pháp XML sẽ được tạo ra nhiều hơn bởi số lượng công việc sáng tạo và chuyển đổi lỗi bạn sẽ phải làm. Vì lợi ích của riêng bạn, google "thư viện XML" và tận dụng công việc của người khác.


3
Nó không phức tạp như C ++.
Cole Johnson

6
@Cole "Cole9" Johnson Tôi cũng sẽ không sử dụng RE để phân tích C ++.
Isaac Rabinovitch

2
Nếu XML là một synchrotron, C ++ sẽ là Máy va chạm Hadron lớn.
Kevin Kostlan

4

Tôi tin này cổ điển có các thông tin bạn đang tìm kiếm. Bạn có thể tìm thấy điểm trong một trong những ý kiến ​​ở đó:

Tôi nghĩ lỗ hổng ở đây là HTML là ngữ pháp Chomsky Loại 2 (ngữ pháp không ngữ cảnh) và RegEx là ngữ pháp Chomsky Loại 3 (biểu thức chính quy). Vì ngữ pháp Loại 2 về cơ bản phức tạp hơn ngữ pháp Loại 3 - bạn không thể hy vọng làm cho nó hoạt động được . Nhưng nhiều người sẽ cố gắng, một số người sẽ tuyên bố thành công và những người khác sẽ tìm ra lỗi và hoàn toàn làm bạn bối rối.

Một số thông tin khác từ Wikipedia: Chomsky HVELy


6
"Biểu thức chính quy" không có ý nghĩa chính xác như nhau trong các cuộc thảo luận ngữ pháp chính thức như ở đây. Hầu hết các công cụ regex còn tồn tại mạnh hơn ngữ pháp Chomsky Loại 3 (ví dụ: kết hợp không tham lam, backrefs). Một số công cụ regex (như Perl's) đã hoàn tất. Đúng là ngay cả những công cụ kém để phân tích cú pháp HTML, nhưng đối số được trích dẫn này không phải là lý do tại sao.
dubiousjim

4

Tôi nghĩ rằng các vấn đề sôi lên:

  1. Regex gần như luôn luôn không chính xác. Có những đầu vào hợp pháp mà nó sẽ không khớp chính xác. Nếu bạn làm việc đủ chăm chỉ, bạn có thể làm cho nó đúng 99% hoặc 99,999%, nhưng làm cho nó đúng 100% là gần như không thể, nếu chỉ vì những điều kỳ lạ mà XML cho phép bằng cách sử dụng các thực thể.

  2. Nếu regex không chính xác, ngay cả đối với 0,00001% đầu vào, thì bạn có vấn đề về bảo mật, bởi vì ai đó có thể khám phá ra một đầu vào sẽ phá vỡ ứng dụng của bạn.

  3. Nếu regex đủ chính xác để bao gồm 99,99% các trường hợp thì nó sẽ hoàn toàn không thể đọc được và không thể nhầm lẫn.

  4. Rất có khả năng một regex sẽ hoạt động rất tệ trên các tệp đầu vào có kích thước vừa phải. Cuộc gặp gỡ đầu tiên của tôi với XML là thay thế một tập lệnh Perl (không chính xác) đã phân tích cú pháp các tài liệu XML đến bằng một trình phân tích cú pháp XML phù hợp và chúng tôi không chỉ thay thế 300 dòng mã không thể đọc được bằng 100 dòng mà mọi người có thể hiểu, nhưng chúng tôi đã cải thiện thời gian phản hồi của người dùng từ 10 giây đến khoảng 0,1 giây.


1

Nói chung, XML không thể được phân tích cú pháp bằng regex vì ngữ pháp XML không có nghĩa là thông thường. Nói một cách đơn giản, regexes không thể đếm (tốt, các regex Perl thực sự có thể đếm được mọi thứ) vì vậy bạn không thể cân bằng các thẻ đóng mở.

Tôi không đồng ý. Nếu bạn sẽ sử dụng đệ quy trong regex, bạn có thể dễ dàng tìm thấy các thẻ mở và đóng.

Ở đây tôi đã đưa ra ví dụ về regex để tránh phân tích lỗi của các ví dụ trong thông điệp đầu tiên.


Đầu tiên, các biểu thức đệ quy không phải là biểu thức chính quy (nếu bạn nhìn vào dấu ngoặc đơn, bạn sẽ thấy rằng tôi thừa nhận rằng các biểu thức của Perl, là đệ quy, có thể đếm các thứ, được yêu cầu để xử lý HTML). Thứ hai, ví dụ của bạn là dành cho XHTML hoặc XML được hình thành tốt. HTML không được hình thành tốt. Thứ ba, bạn phải tự hỏi mình, việc mở rộng và duy trì một trình phân tích cú pháp được viết bằng ngôn ngữ regex đệ quy hay ngôn ngữ lập trình mục đích chung là dễ dàng hơn.
Chas. Owens

Thứ tư, ngay cả ví dụ của bạn bị phá vỡ tầm thường trong khi vẫn là XML hợp lệ. Thêm một khoảng trắng giữa content_block và id và nó không thành công. Tôi chắc chắn rằng nếu tôi dành thêm vài phút nữa tôi sẽ tìm thấy một số lỗi cấu trúc khác trong mã của bạn. Nó không phải là một ý tưởng tốt.
Chas. Owens

1

Tôi đã đưa ra một câu trả lời đơn giản cho vấn đề này ở đây . Mặc dù nó không chiếm 100%, tôi giải thích khả năng của bạn nếu bạn sẵn sàng thực hiện một số công việc tiền xử lý.

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.