Tại sao không thể sử dụng regex để phân tích cú pháp HTML / XML: một lời giải thích chính thức theo thuật ngữ của giáo dân


117

Không có ngày nào trên SO trôi qua mà không có câu hỏi về phân tích cú pháp (X) HTML hoặc XML với các biểu thức chính quy được hỏi.

Mặc dù tương đối dễ dàng để đưa ra các ví dụ chứng minh tính không khả thi của regex cho nhiệm vụ này hoặc với một bộ sưu tập các biểu thức để đại diện cho khái niệm, tôi vẫn không thể tìm thấy trên SO một lời giải thích chính thức về lý do tại sao điều này không thể được thực hiện trong điều kiện.

Những lời giải thích chính thức duy nhất mà tôi có thể tìm thấy cho đến nay trên trang web này có lẽ cực kỳ chính xác, nhưng cũng khá khó hiểu đối với lập trình viên tự học:

lỗ hổng ở đây là HTML là ngữ pháp Chomsky Loại 2 (ngữ pháp không có ngữ cảnh) và RegEx là ngữ pháp Chomsky Loại 3 (biểu thức chính quy)

hoặc là:

Biểu thức chính quy chỉ có thể khớp với ngôn ngữ thông thường nhưng HTML là ngôn ngữ không có ngữ cảnh.

hoặc là:

Một ô tô tự động hữu hạn (là cấu trúc dữ liệu bên dưới một biểu thức chính quy) không có bộ nhớ ngoài trạng thái của nó và nếu bạn có lồng ghép sâu tùy ý, bạn cần một ô tô tự động lớn tùy ý, điều này mâu thuẫn với khái niệm về một ô tô tự động hữu hạn.

hoặc là:

Bổ đề Pumping cho các ngôn ngữ thông thường là lý do tại sao bạn không thể làm điều đó.

[Công bằng mà nói: phần lớn phần giải thích ở trên liên kết đến các trang wikipedia, nhưng những phần này không dễ hiểu hơn chính câu trả lời].

Vì vậy, câu hỏi của tôi là: ai đó có thể vui lòng cung cấp bản dịch theo thuật ngữ của giáo dân về các giải thích chính thức được đưa ra ở trên về lý do tại sao không thể sử dụng regex để phân tích cú pháp (X) HTML / XML không?

CHỈNH SỬA: Sau khi đọc câu trả lời đầu tiên, tôi nghĩ rằng mình nên làm rõ: Tôi đang tìm kiếm một "bản dịch" cũng giải thích ngắn gọn các khái niệm mà nó cố gắng dịch: ở cuối câu trả lời, người đọc nên có một ý tưởng sơ bộ - ví dụ: - "ngôn ngữ thông thường" và "ngữ pháp không theo ngữ cảnh" nghĩa là gì ...


19
Hãy lưu ý rằng trong thuật ngữ khoa học máy tính, "biểu thức chính quy" khác rất nhiều so với "triển khai regex" ngày nay (các công cụ / api mà bạn sử dụng trong một ngôn ngữ lập trình). Cái sau có thể "nhớ" những thứ họ đã gặp và thậm chí có thể khớp với các mẫu (con) được xác định đệ quy, làm cho chúng khớp / phân tích cú pháp / nhận dạng nhiều hơn so với "biểu thức chính quy" trên lý thuyết.
Bart Kiers

1
@Bart: Điều này thực sự chỉ áp dụng cho các ngôn ngữ lạm dụng thuật ngữ "biểu thức chính quy. POSIX ERE hoàn toàn là thông thường.
R .. GitHub DỪNG TRỢ GIÚP LÚC NỮA,

2
@R .., vì vậy, bạn gọi POSIX là "triển khai thời hiện đại": P. Mặc dù vậy, xét về mức độ nghiêm túc: vâng, bạn nói đúng, những điều đó thực sự thường xuyên. Tôi nên nói "... nhiều triển khai regex hiện đại ..." hoặc "... triển khai PCRE regex ..." .
Bart Kiers,

4
Tôi gặp khó khăn trong việc xem xét nghiêm túc các ngôn ngữ lập trình về cơ bản là sử dụng sai ngôn ngữ nghiêm ngặt vì mục đích tiếp thị bản thân cho những lập trình viên thiếu hiểu biết ...
R .. GitHub DỪNG TRỢ GIÚP ICE

3
@R .., thật đáng tiếc khi việc triển khai PCRE được gọi là "cụm từ thông dụng", nhưng việc không coi trọng ngôn ngữ là đã đi quá xa một bước, IMO. Ý tôi là, bạn không sử dụng Perl, Java, Python, Ruby, JavaScript, .NET, v.v. không nghiêm trọng vì điều này?
Bart Kiers,

Câu trả lời:


117

Tập trung vào cái này:

Một ô tô tự động hữu hạn (là cấu trúc dữ liệu bên dưới một biểu thức chính quy) không có bộ nhớ ngoài trạng thái của nó và nếu bạn có lồng ghép sâu tùy ý, bạn cần một ô tô tự động lớn tùy ý, điều này mâu thuẫn với khái niệm về một ô tô tự động hữu hạn.

các định nghĩa của biểu thức thông thường tương đương với thực tế là một bài kiểm tra về việc liệu một chuỗi phù hợp với mô hình có thể được thực hiện bởi một automaton hữu hạn (một automaton khác nhau cho mỗi mẫu). Một automaton hữu hạn không có bộ nhớ - không có ngăn xếp, không có đống, không có băng vô hạn để viết nguệch ngoạc. Tất cả những gì nó có là một số lượng hữu hạn các trạng thái bên trong, mỗi trạng thái có thể đọc một đơn vị đầu vào từ chuỗi đang được kiểm tra và sử dụng nó để quyết định trạng thái nào sẽ chuyển sang tiếp theo. Trong trường hợp đặc biệt, nó có hai trạng thái kết thúc: "có, điều đó đã khớp" và "không, điều đó không khớp".

Mặt khác, HTML có các cấu trúc có thể lồng sâu tùy ý. Để xác định tệp có phải là HTML hợp lệ hay không, bạn cần kiểm tra xem tất cả các thẻ đóng có khớp với thẻ mở trước đó hay không. Để hiểu nó, bạn cần biết phần tử nào đang được đóng. Không có bất kỳ phương tiện nào để "nhớ" những thẻ mở bạn đã thấy, không có cơ hội.

Tuy nhiên, lưu ý rằng hầu hết các thư viện "regex" thực sự cho phép nhiều hơn là chỉ định nghĩa chặt chẽ về biểu thức chính quy. Nếu chúng có thể khớp với các tham chiếu ngược, thì chúng đã vượt ra ngoài một ngôn ngữ thông thường. Vì vậy, lý do tại sao bạn không nên sử dụng thư viện regex trên HTML phức tạp hơn một chút so với thực tế đơn giản là HTML không thông thường.


Ngoài ra còn có một lời giải thích khá tốt về tự động dữ liệu trạng thái hữu hạn ở đây: youtube.com/watch?v=vhiiia1_hC4
GDP2

55

Thực tế HTML không đại diện cho một ngôn ngữ thông thường là một con cá trích đỏ. Biểu thức chính quy và ngôn ngữ thông thường nghe có vẻ giống nhau , nhưng không phải - chúng có chung nguồn gốc, nhưng có một khoảng cách đáng chú ý giữa "ngôn ngữ thông thường" học thuật và sức mạnh phù hợp hiện tại của các động cơ. Trên thực tế, hầu hết tất cả các công cụ biểu thức chính quy hiện đại đều hỗ trợ các tính năng không thông thường - một ví dụ đơn giản là (.*)\1. sử dụng tham chiếu ngược để khớp với một chuỗi ký tự lặp lại - ví dụ: 123123hoặc bonbon. Việc so khớp các cấu trúc đệ quy / cân bằng làm cho những cấu trúc này trở nên thú vị hơn.

Wikipedia đặt điều này một cách độc đáo, trong một trích dẫn của Larry Wall :

'Biểu thức chính quy' [...] chỉ liên quan một chút đến biểu thức chính quy thực. Tuy nhiên, thuật ngữ này đã phát triển với khả năng của các công cụ khớp mẫu của chúng tôi, vì vậy tôi sẽ không cố gắng chống lại sự cần thiết về ngôn ngữ ở đây. Tuy nhiên, tôi thường gọi chúng là "regexes" (hoặc "regexen", khi tôi đang ở trong tâm trạng Anglo-Saxon).

"Biểu thức chính quy chỉ có thể khớp với các ngôn ngữ thông thường", như bạn có thể thấy, không gì khác hơn là một ngụy biện thường được nêu.

Vậy, tại sao không?

Một lý do chính đáng để không đối sánh HTML với biểu thức chính quy là "chỉ vì bạn có thể không có nghĩa là bạn nên làm". Mặc dù có thể có - đơn giản là có những công cụ tốt hơn cho công việc . Đang xem xét:

  • HTML hợp lệ khó / phức tạp hơn bạn nghĩ.
  • Có nhiều loại HTML "hợp lệ" - ví dụ: những gì hợp lệ trong HTML, không hợp lệ trong XHTML.
  • Phần lớn HTML dạng tự do được tìm thấy trên internet không hợp lệ . Các thư viện HTML cũng làm rất tốt việc xử lý những điều này và đã được kiểm tra cho nhiều trường hợp phổ biến này.
  • Rất thường không thể khớp một phần dữ liệu mà không phân tích cú pháp toàn bộ. Ví dụ: bạn có thể đang tìm kiếm tất cả các tiêu đề và kết thúc khớp bên trong một nhận xét hoặc một chuỗi ký tự. <h1>.*?</h1>có thể là một nỗ lực táo bạo trong việc tìm kiếm tiêu đề chính, nhưng nó có thể tìm thấy:

    <!-- <h1>not the title!</h1> -->

    Hoặc thậm chí:

    <script>
    var s = "Certainly <h1>not the title!</h1>";
    </script>

Điểm cuối cùng là quan trọng nhất:

  • Sử dụng trình phân tích cú pháp HTML chuyên dụng tốt hơn bất kỳ regex nào bạn có thể nghĩ ra. Thông thường, XPath cho phép một cách diễn đạt tốt hơn để tìm kiếm dữ liệu bạn cần và việc sử dụng trình phân tích cú pháp HTML dễ dàng hơn nhiều so với những gì hầu hết mọi người nhận ra .

Bạn có thể tìm thấy một bản tóm tắt hay về chủ đề và nhận xét quan trọng về thời điểm kết hợp Regex và HTML có thể phù hợp trong blog của Jeff Atwood: Parsing Html The Cthulhu Way .

Khi nào thì tốt hơn nên sử dụng biểu thức chính quy để phân tích cú pháp HTML?

Trong hầu hết các trường hợp, tốt hơn là sử dụng XPath trên cấu trúc DOM mà một thư viện có thể cung cấp cho bạn. Tuy nhiên, chống lại ý kiến ​​phổ biến, có một số trường hợp tôi thực sự khuyên bạn nên sử dụng regex chứ không phải thư viện phân tích cú pháp:

Đưa ra một số điều kiện sau:

  • Khi bạn cần cập nhật một lần các tệp HTML của mình và bạn biết cấu trúc nhất quán.
  • Khi bạn có một đoạn mã HTML rất nhỏ.
  • Khi bạn không xử lý một tệp HTML mà là một công cụ tạo khuôn mẫu tương tự (có thể rất khó tìm thấy trình phân tích cú pháp trong trường hợp đó).
  • Khi bạn muốn thay đổi các phần của HTML, nhưng không phải tất cả - trình phân tích cú pháp, theo hiểu biết của tôi, không thể trả lời yêu cầu này: nó sẽ phân tích cú pháp toàn bộ tài liệu và lưu toàn bộ tài liệu, thay đổi các phần mà bạn không bao giờ muốn thay đổi.

4
Đây là một đoạn viết rất rõ ràng và độc đáo về thời điểm (không nên) sử dụng regex để phân tích cú pháp HTML, nhưng nó khó có câu trả lời cho câu hỏi của tôi. Tôi có thể đề nghị bạn chuyển nó sang câu hỏi này không? Tôi nghĩ rằng nó sẽ giúp bạn nổi tiếng hơn ở đó nhưng - trên tất cả - tôi nghĩ đó sẽ là nơi mà khách truy cập trong tương lai sẽ thấy nó phù hợp hơn (có một bình luận của @Bart Kiers cho câu hỏi của tôi nhắc nhở khách truy cập về "sức mạnh bổ sung" của động cơ regex hiện đại).
mac,

1
@mac - Cảm ơn rất nhiều. Trên thực tế, tôi đã suy nghĩ về nó. Tôi biết tôi đã không trả lời câu hỏi của bạn, nhưng tôi không nghĩ câu hỏi về cơ bản là đúng - bạn yêu cầu giải thích lý do sai ... Mặc dù vậy, bạn có một ý kiến ​​hay, có thể câu hỏi khác phù hợp hơn ...
Kobi,

19

Bởi vì HTML có thể có lồng ghép không giới hạn <tags><inside><tags and="<things><that><look></like></tags>"></inside></each></other>và regex thực sự không thể đối phó với điều đó bởi vì nó không thể theo dõi lịch sử của những gì nó xuất hiện và đi ra.

Một cấu trúc đơn giản minh họa khó khăn:

<body><div id="foo">Hi there!  <div id="bar">Bye!</div></div></body>

99,9% các quy trình trích xuất dựa trên regex tổng quát sẽ không thể cung cấp cho tôi một cách chính xác mọi thứ bên trong divcùng với ID foo, bởi vì họ không thể nói thẻ đóng cho div đó với thẻ đóng cho bardiv. Đó là bởi vì họ không có cách nào để nói "được rồi, bây giờ tôi đã xuống vị trí thứ hai trong số hai div, vì vậy div đóng tiếp theo mà tôi nhìn thấy sẽ đưa tôi trở lại một div và cái sau đó là thẻ đóng cho đầu tiên" . Các lập trình viên thường phản ứng bằng cách tạo ra các regex trong trường hợp đặc biệt cho tình huống cụ thể, sau đó sẽ bị hỏng ngay khi có nhiều thẻ hơn được đưa vào bên trong foovà phải được giải mã với chi phí rất lớn về thời gian và sự thất vọng. Đây là lý do tại sao mọi người phát điên về toàn bộ sự việc.


1
Đánh giá cao câu trả lời, nhưng câu hỏi của tôi không phải là "tại sao tôi không thể sử dụng regex ...". Câu hỏi của tôi là về "dịch" các giải thích chính thức mà tôi đã cung cấp! :)
mac

5
Đây là bản dịch của tất cả chúng theo một nghĩa nào đó, gần giống nhất là "Cụm từ thông dụng chỉ có thể khớp với các ngôn ngữ thông thường nhưng HTML là một ngôn ngữ không có ngữ cảnh" và là một về tự động hữu hạn. Đó thực sự là tất cả cùng một lý do.
Ianus Chiaroscuro,

Xin lỗi, có thể tôi chưa hiểu rõ câu hỏi của mình (chúng tôi hoan nghênh các đề xuất để cải thiện câu hỏi!). Nhưng tôi đang tìm kiếm một câu trả lời cũng giải thích cho "bản dịch". Câu trả lời của bạn không làm rõ khái niệm 'ngôn ngữ thông thường' và 'ngôn ngữ không theo ngữ cảnh' ...
mac

5
Việc giải thích các thuật ngữ đó sẽ mang tính kỹ thuật giống như chính thuật ngữ đó, và làm xao nhãng ý nghĩa thực tế mà tất cả ngôn ngữ chính xác đang đạt được, đó là những gì tôi đã đăng.
Ianus Chiaroscuro

4
<(\w+)(?:\s+\w+="[^"]*")*>(?R)*</\1>|[\w\s!']+phù hợp với mẫu mã của bạn.
Kobi,

9

Một ngôn ngữ thông thường là một ngôn ngữ có thể được khớp bởi một máy trạng thái hữu hạn.

(Hiểu về máy Trạng thái hữu hạn, máy đẩy xuống và máy Turing về cơ bản là chương trình giảng dạy của Khóa học CS đại học năm thứ tư.)

Hãy xem xét máy sau đây, máy nhận dạng chuỗi "hi".

(Start) --Read h-->(A)--Read i-->(Succeed)
  \                  \
   \                  -- read any other value-->(Fail) 
    -- read any other value-->(Fail)

Đây là một máy đơn giản để nhận dạng một ngôn ngữ thông thường; Mỗi biểu thức trong ngoặc là một trạng thái, và mỗi mũi tên là một chuyển đổi. Việc xây dựng một máy như thế này sẽ cho phép bạn kiểm tra bất kỳ chuỗi đầu vào nào so với ngôn ngữ thông thường - do đó, là một biểu thức chính quy.

HTML đòi hỏi bạn phải biết nhiều hơn chỉ là bạn đang ở trạng thái nào - nó yêu cầu lịch sử về những gì bạn đã thấy trước đây, để khớp với lồng thẻ. Bạn có thể thực hiện điều này nếu bạn thêm một ngăn xếp vào máy, nhưng sau đó nó không còn "thường xuyên" nữa. Đây được gọi là máy Đẩy xuống và nhận dạng ngữ pháp.


2
"Hiểu về máy Trạng thái hữu hạn, máy Đẩy xuống và Máy Turing về cơ bản là chương trình giảng dạy của Khóa học CS 300 cấp độ." Tôi hiểu đây là một nỗ lực để trình bày mức độ khó / nâng cao của chủ đề, nhưng tôi không quen với hệ thống trường học mà bạn đang đề cập, bạn có thể vui lòng giải thích theo cách không cụ thể của quốc gia không? Cảm ơn bạn! :)
mac

1
Tôi đã cập nhật nó. Tôi không biết rằng nó quá khó hiểu, chỉ cần giải thích trong một bài đăng tràn ngăn xếp.
Sean McMillan,

6

Biểu thức chính quy là một máy có số trạng thái rời rạc hữu hạn (và thường là khá nhỏ).

Để phân tích cú pháp XML, C hoặc bất kỳ ngôn ngữ nào khác có lồng các phần tử ngôn ngữ tùy ý, bạn cần nhớ mức độ sâu sắc của bạn. Đó là, bạn phải có khả năng đếm dấu ngoặc nhọn / dấu ngoặc nhọn / thẻ.

Bạn không thể đếm với bộ nhớ hữu hạn. Có thể có nhiều mức ngoặc nhọn hơn mức bạn có! Bạn có thể phân tích cú pháp một tập hợp con của ngôn ngữ hạn chế số lượng cấp độ lồng nhau, nhưng nó sẽ rất tẻ nhạt.


6

Ngữ pháp là một định nghĩa chính thức về nơi các từ có thể đi đến. Ví dụ, tính từ đứng trước danh từ in English grammar, nhưng theo sau danh từ en la gramática española. Không có ngữ cảnh có nghĩa là máy chấm điểm phổ biến trong mọi ngữ cảnh. Nhạy cảm với ngữ cảnh có nghĩa là có các quy tắc bổ sung trong các ngữ cảnh nhất định.

Ví dụ, trong C #, usingcó nghĩa là một cái gì đó khác ở using System;đầu tệp, hơn using (var sw = new StringWriter (...)). Một ví dụ có liên quan hơn là đoạn mã sau trong mã:

void Start ()
{
    string myCode = @"
    void Start()
    {
       Console.WriteLine (""x"");
    }
    ";
}

Đây là một câu trả lời dễ hiểu
Một người

Nhưng không có ngữ cảnh không có nghĩa là thường xuyên. Ngôn ngữ của paranthesis phù hợp là không có ngữ cảnh, nhưng không chính quy.
Taemyr

Điều cần bổ sung là các biểu thức chính quy (trừ khi bạn thêm các phần mở rộng như có trong Perl) tương đương với các ngữ pháp thông thường , có nghĩa là chúng không thể mô tả các cấu trúc lồng nhau sâu tùy ý như dấu ngoặc đơn cân đối sâu tùy ý hoặc thẻ mở và đóng phần tử HTML.
reinierpost

4

Có một lý do thực tế khác cho việc không sử dụng biểu thức chính quy để phân tích cú pháp XML và HTML mà không liên quan gì đến lý thuyết khoa học máy tính: biểu thức chính quy của bạn sẽ phức tạp một cách ẩn ý hoặc nó sẽ sai.

Ví dụ: rất tốt khi viết một biểu thức chính quy để khớp

<price>10.65</price>

Nhưng nếu mã của bạn là chính xác, thì:

  • Nó phải cho phép khoảng trắng sau tên phần tử trong cả thẻ bắt đầu và thẻ kết thúc

  • Nếu tài liệu nằm trong một không gian tên, thì nó sẽ cho phép bất kỳ tiền tố không gian tên nào được sử dụng

  • Nó có thể sẽ cho phép và bỏ qua bất kỳ thuộc tính không xác định nào xuất hiện trong thẻ bắt đầu (tùy thuộc vào ngữ nghĩa của từ vựng cụ thể)

  • Nó có thể cần cho phép khoảng trắng trước và sau giá trị thập phân (một lần nữa, tùy thuộc vào các quy tắc chi tiết của từ vựng XML cụ thể).

  • Nó không được khớp với thứ gì đó trông giống như một phần tử, nhưng thực sự nằm trong phần nhận xét hoặc CDATA (điều này trở nên đặc biệt quan trọng nếu có khả năng dữ liệu độc hại cố gắng đánh lừa trình phân tích cú pháp của bạn).

  • Nó có thể cần cung cấp chẩn đoán nếu đầu vào không hợp lệ.

Tất nhiên một số điều này phụ thuộc vào các tiêu chuẩn chất lượng bạn đang áp dụng. Chúng tôi thấy rất nhiều vấn đề trên StackOverflow với việc mọi người phải tạo XML theo một cách cụ thể (ví dụ: không có khoảng trắng trong các thẻ) bởi vì nó đang được đọc bởi một ứng dụng yêu cầu nó phải được viết theo một cách cụ thể. Nếu mã của bạn có bất kỳ loại lâu dài nào thì điều quan trọng là nó phải có thể xử lý XML đến được viết theo bất kỳ cách nào mà tiêu chuẩn XML cho phép, và không chỉ là một tài liệu đầu vào mẫu mà bạn đang kiểm tra mã của mình.


2

Theo nghĩa lý thuyết thuần túy, các biểu thức chính quy không thể phân tích cú pháp XML. Chúng được định nghĩa theo cách cho phép chúng không có bộ nhớ về bất kỳ trạng thái nào trước đó, do đó ngăn không cho khớp chính xác của một thẻ tùy ý và chúng không thể thâm nhập vào độ sâu lồng tùy ý, vì việc lồng sẽ cần được tích hợp vào biểu thức chính quy.

Tuy nhiên, trình phân tích cú pháp regex hiện đại được xây dựng cho tiện ích của chúng đối với nhà phát triển, thay vì tuân theo một định nghĩa chính xác. Như vậy, chúng ta có những thứ như tham chiếu ngược và đệ quy sử dụng kiến ​​thức về các trạng thái trước đó. Sử dụng những thứ này, việc tạo một regex có thể khám phá, xác thực hoặc phân tích cú pháp XML rất đơn giản.

Hãy xem xét ví dụ,

(?:
    <!\-\-[\S\s]*?\-\->
    |
    <([\w\-\.]+)[^>]*?
    (?:
        \/>
        |
        >
        (?:
            [^<]
            |
            (?R)
        )*
        <\/\1>
    )
)

Thao tác này sẽ tìm thấy thẻ hoặc nhận xét XML được định dạng đúng tiếp theo và nó sẽ chỉ tìm thấy nó nếu toàn bộ nội dung của nó được định dạng đúng. (Biểu thức này đã được kiểm tra bằng Notepad ++, sử dụng thư viện regex của Boost C ++, gần giống với PCRE.)

Đây là cách nó hoạt động:

  1. Đoạn đầu tiên khớp với một bình luận. Điều này là cần thiết trước tiên để nó xử lý bất kỳ mã nhận xét nào có thể gây ra treo máy.
  2. Nếu không khớp, nó sẽ tìm kiếm phần đầu của thẻ. Lưu ý rằng nó sử dụng dấu ngoặc đơn để ghi tên.
  3. Thẻ này sẽ kết thúc bằng a />, do đó hoàn thành thẻ hoặc sẽ kết thúc bằng a >, trong trường hợp đó, thẻ sẽ tiếp tục bằng cách kiểm tra nội dung của thẻ.
  4. Nó sẽ tiếp tục phân tích cú pháp cho đến khi đạt đến a <, tại thời điểm đó, nó sẽ đệ quy trở lại phần đầu của biểu thức, cho phép nó xử lý một bình luận hoặc một thẻ mới.
  5. Nó sẽ tiếp tục qua vòng lặp cho đến khi nó đến cuối văn bản hoặc ở điểm <mà nó không thể phân tích cú pháp. Tất nhiên, việc không khớp sẽ khiến quá trình bắt đầu lại. Nếu không, <có lẽ là đầu của thẻ đóng cho lần lặp này. Sử dụng tham chiếu ngược bên trong thẻ đóng <\/\1>, nó sẽ khớp với thẻ mở cho lần lặp hiện tại (độ sâu). Chỉ có một nhóm bắt giữ, vì vậy trận đấu này là một vấn đề đơn giản. Điều này làm cho nó độc lập với tên của các thẻ được sử dụng, mặc dù bạn có thể sửa đổi nhóm chụp để chỉ chụp các thẻ cụ thể, nếu bạn cần.
  6. Tại thời điểm này, nó sẽ khởi động ra khỏi đệ quy hiện tại, lên cấp độ tiếp theo hoặc kết thúc bằng một trận đấu.

Ví dụ này giải quyết các vấn đề xử lý khoảng trắng hoặc xác định nội dung có liên quan thông qua việc sử dụng các nhóm ký tự chỉ phủ định <hoặc >, hoặc trong trường hợp các nhận xét, bằng cách sử dụng [\S\s], sẽ khớp với bất kỳ thứ gì, bao gồm ký tự xuống dòng và các dòng mới, ngay cả trong một dòng , tiếp tục cho đến khi đạt đến a -->. Do đó, nó đơn giản coi mọi thứ là hợp lệ cho đến khi nó đạt được điều gì đó có ý nghĩa.

Đối với hầu hết các mục đích, một regex như thế này không đặc biệt hữu ích. Nó sẽ xác nhận rằng XML được định dạng đúng cách, nhưng đó là tất cả những gì nó thực sự sẽ làm, và nó không tính đến các thuộc tính (mặc dù đây sẽ là một bổ sung dễ dàng). Nó chỉ đơn giản như vậy vì nó đưa ra các vấn đề trong thế giới thực như thế này, cũng như các định nghĩa về tên thẻ. Lắp nó vào mục đích sử dụng thực sự sẽ khiến nó trở nên giống một con thú hơn nhiều. Nói chung, một trình phân tích cú pháp XML thực sự sẽ vượt trội hơn nhiều. Cái này có lẽ phù hợp nhất để dạy cách hoạt động của đệ quy.

Câu chuyện ngắn: sử dụng trình phân tích cú pháp XML cho công việc thực tế và sử dụng trình này nếu bạn muốn thử với regex.


3
Tuyên bố rằng regex này sẽ chỉ khớp nếu đầu vào được định dạng tốt là không chính xác. Nó không kiểm tra các tên đó có phải là các tên XML hợp lệ hay không, nó không kiểm tra các thuộc tính, nó không kiểm tra các tham chiếu thực thể và ký tự, nó không xử lý CDATA hoặc hướng dẫn xử lý. Khi bạn nói rằng nó đã được kiểm tra, tôi rất nghi ngờ rằng nó đã được kiểm tra trên bất kỳ thứ gì giống như bộ kiểm tra sự tuân thủ XML. Đó là vấn đề với tất cả các nỗ lực xử lý XML bằng các regex mà tôi từng thấy: chúng hoạt động với một số lượng nhỏ đầu vào, nhưng không phải với bất kỳ XML nào có thể được chuyển đến ứng dụng của bạn một cách hợp pháp.
Michael Kay

2
Ngoài ra, có những đầu vào được định hình tốt mà regex không khớp. Ví dụ: nó không cho phép khoảng trắng sau tên trong thẻ kết thúc. Hầu hết các trục trặc này đều có thể dễ dàng sửa chữa, nhưng một khi bạn khắc phục TẤT CẢ các trục trặc, bạn sẽ có thứ hoàn toàn không thể sử dụng được. Và tất nhiên gotcha thực sự là bạn không chỉ muốn trình phân tích cú pháp đưa ra câu trả lời có / không, bạn muốn nó chuyển thông tin đến một ứng dụng có chức năng hữu ích với nó.
Michael Kay

0

Không phân tích cú pháp XML / HTML bằng regex, hãy sử dụng trình phân tích cú pháp XML / HTML thích hợp và truy vấn.

học thuyết :

Theo lý thuyết biên dịch, XML / HTML không thể được phân tích cú pháp bằng regex dựa trên máy trạng thái hữu hạn . Do cấu trúc phân cấp của XML / HTML, bạn cần sử dụng tự động đẩy xuống và thao tác ngữ pháp LALR bằng công cụ như YACC .

realLife © ® ™ công cụ hàng ngày trong một :

Bạn có thể sử dụng một trong những cách sau:

xmllint thường được cài đặt theo mặc định với libxml2, xpath1 (kiểm tra trình bao bọc của tôi để có đầu ra được phân cách dòng mới

xmlstarlet có thể chỉnh sửa, chọn, chuyển đổi ... Không được cài đặt theo mặc định, xpath1

xpath được cài đặt qua mô-đun của perl XML :: XPath, xpath1

xidel xpath3

saxon-lint dự án của riêng tôi, trình bao bọc trên thư viện Java Saxon-HE của @Michael Kay, xpath3

hoặc bạn có thể sử dụng ngôn ngữ cấp cao và ngôn ngữ phù hợp, tôi nghĩ đến:

's lxml( from lxml import etree)

's XML::LibXML, XML::XPath, XML::Twig::XPath,HTML::TreeBuilder::XPath

, hãy kiểm tra ví dụ này

DOMXpath, hãy kiểm tra ví dụ này


Kiểm tra: Sử dụng biểu thức chính quy với thẻ HTML

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.