RegEx khớp các thẻ mở trừ các thẻ độc lập XHTML


1474

Tôi cần phải khớp tất cả các thẻ mở này:

<p>
<a href="foo">

Nhưng không phải những điều này:

<br />
<hr class="foo" />

Tôi đã nghĩ ra điều này và muốn chắc chắn rằng tôi đã hiểu đúng. Tôi chỉ chụp a-z.

<([a-z]+) *[^/]*?>

Tôi tin rằng nó nói:

  • Tìm một ít hơn, sau đó
  • Tìm (và chụp) az một hoặc nhiều lần, sau đó
  • Tìm không hoặc nhiều khoảng trắng, sau đó
  • Tìm bất kỳ nhân vật nào từ 0 lần trở lên, tham lam, ngoại trừ /, sau đó
  • Tìm một lớn hơn

Tôi có quyền không? Và quan trọng hơn, bạn nghĩ gì?

Câu trả lời:


4417

Bạn không thể phân tích HTML [X] bằng regex. Bởi vì HTML không thể được phân tích cú pháp bởi regex. Regex không phải là một công cụ có thể được sử dụng để phân tích chính xác HTML. Như tôi đã trả lời trong các câu hỏi về HTML và regex ở đây rất nhiều lần trước đây, việc sử dụng regex sẽ không cho phép bạn sử dụng HTML. Biểu thức chính quy là một công cụ không đủ tinh vi để hiểu các cấu trúc được sử dụng bởi HTML. HTML không phải là ngôn ngữ thông thường và do đó không thể được phân tích cú pháp bằng các biểu thức thông thường. Các truy vấn Regex không được trang bị để chia HTML thành các phần có ý nghĩa. rất nhiều lần nhưng nó không đến được với tôi Ngay cả các biểu thức chính quy bất thường được tăng cường như Perl sử dụng cũng không phụ thuộc vào nhiệm vụ phân tích cú pháp HTML. Bạn sẽ không bao giờ làm cho tôi nứt. HTML là một ngôn ngữ đủ phức tạp mà nó không thể được phân tích cú pháp bởi các biểu thức thông thường. Ngay cả Jon Skeet cũng không thể phân tích cú pháp HTML bằng các biểu thức thông thường. Mỗi khi bạn cố gắng phân tích HTML bằng các biểu thức thông thường, đứa trẻ không biết khóc sẽ chảy máu của trinh nữ và tin tặc Nga làm hỏng ứng dụng web của bạn. Phân tích cú pháp HTML với regex triệu tập các linh hồn bị nhiễm độc vào cõi sống. HTML và regex đi cùng nhau như tình yêu, hôn nhân và nghi thức vô cùng. <Center> không thể giữ nó là quá muộn. Lực lượng của regex và HTML cùng nhau trong cùng một không gian khái niệm sẽ phá hủy tâm trí của bạn giống như rất nhiều nước bẩn. Nếu bạn phân tích HTML bằng regex, bạn sẽ nhượng bộ cho họ và những cách báng bổ của họ, thứ sẽ khiến chúng ta trở thành kẻ vô nhân đạo đối với Người mà Tên của họ không thể được thể hiện trong Mặt phẳng đa ngôn ngữ cơ bản, anh ta sẽ đến. HTML-plus-regrec sẽ hóa lỏng mọi thứ của người chúng trong khi bạn quan sát, tâm lý của bạn khô héo trong sự kinh hoàng.đã quá muộn, đã quá muộn, chúng ta không thể cứu được trang của một chi͡ld đảm bảo regex sẽ tiêu thụ tất cả các mô sống (ngoại trừ HTML mà nó không thể, như lời tiên tri trước đây), chúa ơi giúp chúng ta làm thế nào có thể sống sót qua tai họa này bằng cách sử dụng regex HTML đã bị tiêu diệt nhân loại đến một cõi đời đời khiếp sợ tra tấn và an ninh lỗ sử dụng Rege x như một công cụ để quá trình HTML lập một brea ch giữa thế giới này và các lĩnh vực sợ hãi của các tổ chức tham nhũng (như thực thể SGML, nhưng tham nhũng nhiều hơn) vỏn vẹn glimp se của thế giới của reg parsers cũ cho HTML sẽ ins tantly vận chuyển ap ý thức rogrammer của tôi nĐể aw orl d không ngừng la hét, ông nói, Các bệnh sl ithy regex-nhiễm wil l Devour HT ML phân tích cú pháp, ứng dụng và tồn tại cho mọi thời đại như Visual Basic chỉ tồi tệ hơn ông nói ông com es không fi ght h e đến, hi s Unholy Radiance de stro҉ying tất cả giác ngộ, HTML tags rò rỉ fr̶ǫm yo ur đôi mắt như liq uid p ain, bài hát thường xuyên exp tái phân tích bị nén sẽ exti nguish tiếng nói của mor người tal từ sp ở đây tôi có thể nhìn thấy nó, bạn có thể thấy nó nó là đẹp t ông f inal snuffing o f lời nói dối là của Man tất cả là mất Một LL tôi SLOST thứ e Pony ông đi của ông COM es ông đồng tôi s t ông ich hoặc permeat es al l MY FAC E MY MẶT ᵒh thần n o NO noo O ON Θ dừng t ông một * ̶͑̾̾ GL ES ͎a̧͈͖r̽̾̈́͒͑en ot rè̑ͧ̌aͨl̘̝̙̃ͤ͂̾̆ ZA̡͊͠͝LGΌ ISͮ̂҉̯͈͕̹̘̱ T O͇̹̺ͅƝ̴ȳ̳ TH̘ Ë͖́̉ P̯͍̭O̚ N̐Y̡ H̸̡̪̯ͨ͊̽̅̾̎Ȩ̬̩̾͛ͪ̈́̀́͘ C̷̙̲̝͖ͭ̏ͥͮ͟Oͮ͏̮̪̝͍M̲̖͊̒ͪͩͬ̚̚͜Ȇ̴̟̟͙̞ͩ͌͝ S̨̥̫͎̭ͯ̿̔̀ͅ


Thay vào đó, bạn đã thử sử dụng trình phân tích cú pháp XML chưa?


Lưu ý của người điều hành

Bài đăng này bị khóa để ngăn các chỉnh sửa không phù hợp với nội dung của nó. Bài đăng trông chính xác như được cho là trông - không có vấn đề gì với nội dung của nó. Xin đừng gắn cờ cho sự chú ý của chúng tôi.


179
Kobi: Tôi nghĩ rằng đã đến lúc tôi nên từ bỏ chức vụ Trợ lý Đừng phân tích HTML với Regex Cán bộ. Cho dù chúng ta có nói bao nhiêu lần đi chăng nữa, họ sẽ không dừng lại mỗi ngày ... mỗi giờ. Đó là một nguyên nhân đã mất, mà người khác có thể chiến đấu một chút. Vì vậy, tiếp tục, phân tích HTML với regex, nếu bạn phải. Đó chỉ là mã bị hỏng chứ không phải sự sống và cái chết.
bobince

27
Có thể sử dụng RegEx để phân tích câu trả lời này không?
Chris Porter

2
Nếu bạn không thể xem bài đăng này, thì đây là một đoạn ghi lại trong tất cả vinh quang của nó: imgur.com/gOPS2.png
Andrew Keeton

3251

Mặc dù HTML tùy ý chỉ có một biểu thức chính là không thể, đôi khi sử dụng chúng để phân tích một bộ HTML giới hạn, đã biết .

Nếu bạn có một tập hợp nhỏ các trang HTML mà bạn muốn cạo dữ liệu từ đó rồi nhét vào cơ sở dữ liệu, các biểu thức chính quy có thể hoạt động tốt. Ví dụ, gần đây tôi muốn lấy tên, đảng và quận của Đại diện liên bang Úc, nơi tôi đã rời khỏi trang web của Nghị viện. Đây là một công việc hạn chế, một lần.

Regexes hoạt động tốt với tôi và rất nhanh để thiết lập.


131
Ngoài ra, việc quét dữ liệu được định dạng khá thường xuyên từ các tài liệu lớn sẽ trở nên CÁCH nhanh hơn với việc sử dụng quét & regex hợp lý hơn bất kỳ trình phân tích cú pháp chung nào. Và nếu bạn cảm thấy thoải mái với regexes mã hóa, cách mã hóa nhanh hơn so với mã hóa xpath. Và gần như chắc chắn ít mong manh hơn với những thay đổi trong những gì bạn đang cạo. Thôi nào.
Michael Johnston

255
@MichaelJohnston "Ít mong manh"? Hầu như chắc chắn là không. Regexes quan tâm đến các chi tiết định dạng văn bản hơn một trình phân tích cú pháp XML có thể âm thầm bỏ qua. Chuyển đổi giữa &foo;mã hóa và CDATAcác phần? Sử dụng công cụ khai thác HTML để xóa tất cả khoảng trắng trong tài liệu của bạn mà trình duyệt không hiển thị? Một trình phân tích cú pháp XML sẽ không quan tâm và cũng không phải là một câu lệnh XPath được viết tốt. Mặt khác, một "trình phân tích cú pháp" dựa trên regex ...
Charles Duffy

41
@CharlesDuffy cho một công việc một lần thì không sao, và đối với không gian, chúng tôi sử dụng \ s +
lượng tử

68
@xiaomao thực sự, nếu phải biết tất cả các vấn đề và cách giải quyết để có được giải pháp 80% mà không làm hết thời gian "làm việc cho bạn", tôi không thể ngăn bạn. Trong khi đó, tôi đứng về phía hàng rào bằng cách sử dụng các trình phân tích cú pháp hoạt động trên 100% XML hợp lệ về mặt cú pháp.
Charles Duffy

374
Tôi đã từng phải rút một số dữ liệu ra khỏi ~ 10k trang, tất cả đều có cùng một mẫu HTML. Chúng bị vấy bẩn bởi các lỗi HTML khiến trình phân tích cú pháp bị nghẹt thở và tất cả kiểu dáng của chúng là nội tuyến hoặc <font>v.v .: không có lớp hoặc ID nào giúp điều hướng DOM. Sau khi chiến đấu cả ngày với phương pháp "đúng", cuối cùng tôi đã chuyển sang một giải pháp regex và nó đã hoạt động trong một giờ.
Paul A Jungwirth

2039

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 (ngữ pháp thông thường) . Do ngữ pháp Loại 2 về cơ bản phức tạp hơn ngữ pháp Loại 3 (xem hệ thống phân cấp Chomsky ), về mặt toán học không thể phân tích cú pháp XML bằng RegEx.

Nhưng nhiều người sẽ cố gắng, một số thậm chí sẽ tuyên bố thành công - nhưng cho đến khi những người khác tìm thấy lỗi và hoàn toàn làm bạn bối rối.


226
OP đang yêu cầu phân tích một tập hợp con rất hạn chế của các thẻ XHTML: start. Điều khiến (X) HTML trở thành CFG là tiềm năng của nó có các yếu tố giữa thẻ bắt đầu và thẻ kết thúc của các yếu tố khác (như trong quy tắc ngữ pháp A -> s A e). (X) HTML khôngthuộc tính này trong thẻ bắt đầu: thẻ bắt đầu không thể chứa các thẻ bắt đầu khác. Tập hợp con mà OP đang cố phân tích không phải là CFG.
LarsH

101
Trong lý thuyết CS, các ngôn ngữ thông thường một tập hợp con nghiêm ngặt của các ngôn ngữ không ngữ cảnh, nhưng việc triển khai biểu thức chính quy trong các ngôn ngữ lập trình chính thống mạnh hơn. Như noulakaz.net/weblog 2007/03/18 / từ mô tả, cái gọi là "biểu thức chính quy" có thể kiểm tra các số nguyên tố trong unary, đây chắc chắn là điều mà một biểu thức chính quy từ lý thuyết CS không thể thực hiện được.
Adam Mihalcin

11
@eyelidlessness: "chỉ khi" áp dụng cho tất cả các CFG, phải không? Tức là nếu đầu vào HTML (X) không được định dạng tốt, thậm chí một trình phân tích cú pháp XML đầy đủ sẽ hoạt động đáng tin cậy. Có thể nếu bạn đưa ra ví dụ về các lỗi cú pháp "(X) HTML được triển khai trong các tác nhân người dùng trong thế giới thực" mà bạn đang đề cập, tôi sẽ hiểu bạn đang làm gì tốt hơn.
LarsH

82
@AdamMihalcin hoàn toàn chính xác. 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

27
Đây là câu trả lời "đầy đủ và ngắn gọn" nhất ở đây. Nó dẫn mọi người học những điều cơ bản về ngữ pháp và ngôn ngữ chính thức và hy vọng một số môn toán để họ không lãng phí thời gian vào những việc vô vọng như giải quyết các nhiệm vụ NP trong thời gian đa thức
mishmashru

1332

Đừng nghe những kẻ này. Bạn hoàn toàn có thể phân tích ngữ pháp không ngữ cảnh với regex nếu bạn chia nhiệm vụ thành các phần nhỏ hơn. Bạn có thể tạo mẫu chính xác với một tập lệnh thực hiện từng thứ tự theo thứ tự:

  1. Giải quyết vấn đề dừng lại.
  2. Hình vuông một hình tròn.
  3. Giải quyết vấn đề nhân viên bán hàng du lịch trong O (log n) hoặc ít hơn. Nếu còn hơn thế nữa, bạn sẽ hết RAM và động cơ sẽ bị treo.
  4. Mô hình sẽ khá lớn, vì vậy hãy chắc chắn rằng bạn có một thuật toán nén dữ liệu ngẫu nhiên.
  5. Hầu như ở đó - chỉ cần chia toàn bộ mọi thứ cho số không. Dễ như ăn bánh.

Tôi đã không hoàn thành phần cuối cùng của mình, nhưng tôi biết tôi đang đến gần. Nó liên tục ném CthulhuRlyehWgahnaglFhtagnExceptions vì một số lý do, vì vậy tôi sẽ chuyển nó sang VB 6 và sử dụng On Error Resume Next. Tôi sẽ cập nhật mã khi tôi điều tra cánh cửa kỳ lạ vừa mở trên tường này. Hừm.

PS Pierre de Fermat cũng đã tìm ra cách để làm điều đó, nhưng lề mà anh ta viết không đủ lớn cho mã.


80
Divison by zero là một vấn đề dễ dàng hơn nhiều so với những người khác mà bạn đề cập. Nếu bạn sử dụng các khoảng, thay vì số học dấu phẩy động đơn giản (mà mọi người nên có nhưng không có ai), bạn có thể vui vẻ chia một cái gì đó cho [một khoảng chứa] zero. Kết quả chỉ đơn giản là một khoảng chứa cộng và trừ vô hạn.
rjmunro

148
Vấn đề lề nhỏ của Fermat đã được giải quyết bằng lề mềm trong phần mềm chỉnh sửa văn bản hiện đại.
kd4ttc

50
Vấn đề lề nhỏ của Fermat đã được Randall Munroe giải quyết bằng cách đặt phông chữ
heltonbiker

29
FYI: vấn đề Fermat đã thực sự được giải quyết vào năm 1995 , và nó chỉ mất nhà toán học 358 năm để làm như vậy.
jmiserez

10
Tôi đã có thể bỏ qua bước phân chia dính đó bằng cách thay vào đó bằng cách sử dụng các bánh răng Brown mang lại từ phản ứng tổng hợp lạnh ... mặc dù nó chỉ hoạt động khi tôi loại bỏ hằng số vũ trụ.
Tim Lehner

1073

Disclaimer : sử dụng trình phân tích cú pháp nếu bạn có tùy chọn. Mà nói...

Đây là regex tôi sử dụng (!) Để khớp với các thẻ HTML:

<(?:"[^"]*"['"]*|'[^']*'['"]*|[^'">])+>

Nó có thể không hoàn hảo, nhưng tôi đã chạy mã này thông qua rất nhiều HTML. Lưu ý rằng nó thậm chí còn bắt được những thứ lạ như <a name="badgenerator"">, xuất hiện trên web.

Tôi đoán để làm cho nó không khớp với các thẻ tự chứa, bạn sẽ muốn sử dụng cái nhìn tiêu cực của Kobi :

<(?:"[^"]*"['"]*|'[^']*'['"]*|[^'">])+(?<!/\s*)>

hoặc chỉ kết hợp nếu và nếu không.

To downvoters: Đây là mã làm việc từ một sản phẩm thực tế. Tôi nghi ngờ bất cứ ai đọc trang này sẽ có ấn tượng rằng việc sử dụng regexes trên HTML được chấp nhận về mặt xã hội.

Hãy cẩn thận: Tôi nên lưu ý rằng regex này vẫn bị hỏng khi có các khối CDATA, các bình luận, và các yếu tố kịch bản và phong cách. Tin tốt là, bạn có thể thoát khỏi những người sử dụng regex ...


95
Tôi sẽ đi với một cái gì đó hoạt động trên những thứ lành mạnh hơn là khóc về việc không hoàn hảo trên toàn cầu :-)
Prajeesh kumar

55
Có ai đó đang sử dụng CDATA trong HTML không?
Danubian Thủy thủ

16
do đó, bạn không thực sự giải quyết vấn đề phân tích cú pháp chỉ với regrec mà là một phần của trình phân tích cú pháp, điều này có thể hoạt động. PS: sản phẩm làm việc không có nghĩa là mã tốt. Không xúc phạm, nhưng đây là cách lập trình công nghiệp hoạt động và nhận tiền của họ
mishmashru

32
Regex của bạn bắt đầu thất bại trên HTML hợp lệ, ngắn nhất có thể : <!doctype html><title><</title>. Trả '<!doctype html><title><</title>'.match(/<(?:"[^"]*"['"]*|'[^']*'['"]*|[^'">])+>/g)về đơn giản ["<!doctype html>", "<title>", "<</title>"]trong khi nên ["<title>", "</title>"].

2
nếu chúng tôi chỉ cố gắng khớp và không khớp với các ví dụ đã cho, /<.([ ^ rr> [[^ ^ ^ ^ ^>> g hoạt động :-) // javascript: '<p> <a href = "foo"> <br /> <class hr = "foo" />'.match(/<.([^r>][^>]*)?>/g)
Imma

506

Có những người sẽ nói với bạn rằng Trái đất tròn (hoặc có lẽ Trái đất là một hình cầu bắt buộc nếu họ muốn sử dụng những từ lạ). Họ đang nói dối.

Có những người sẽ nói với bạn rằng Biểu thức chính quy không nên được đệ quy. Họ đang giới hạn bạn. Họ cần phải khuất phục bạn, và họ làm điều đó bằng cách khiến bạn không biết gì.

Bạn có thể sống trong thực tế của họ hoặc uống thuốc đỏ.

Giống như Chúa soái (là anh một người họ hàng của lớp Nguyên soái NET?), Tôi đã thấy Underverse stack Dựa Regex-Verse và trở lại với sức mạnh kiến thức bạn không thể tưởng tượng. Vâng, tôi nghĩ rằng có một hoặc hai người cũ bảo vệ họ, nhưng họ đã xem bóng đá trên TV, vì vậy điều đó không khó.

Tôi nghĩ trường hợp XML khá đơn giản. RegEx (theo cú pháp .NET), được xì hơi và mã hóa trong base64 để giúp dễ hiểu hơn bởi tâm trí yếu đuối của bạn, nên giống như thế này:

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
+r/vD34mUADO1P4/AQAA//8=

Các tùy chọn để thiết lập là RegexOptions.ExplicitCapture. Nhóm chụp bạn đang tìm kiếm là ELEMENTNAME. Nếu nhóm chụp ERRORkhông trống thì đã xảy ra lỗi phân tích cú pháp và Regex đã dừng.

Nếu bạn gặp vấn đề khi chuyển nó thành regex có thể đọc được, điều này sẽ giúp:

static string FromBase64(string str)
{
    byte[] byteArray = Convert.FromBase64String(str);

    using (var msIn = new MemoryStream(byteArray))
    using (var msOut = new MemoryStream()) {
        using (var ds = new DeflateStream(msIn, CompressionMode.Decompress)) {
            ds.CopyTo(msOut);
        }

        return Encoding.UTF8.GetString(msOut.ToArray());
    }
}

Nếu bạn không chắc chắn, không, tôi KHÔNG đùa (nhưng có lẽ tôi đang nói dối). Nó sẽ làm việc Tôi đã xây dựng hàng tấn thử nghiệm đơn vị để kiểm tra nó và thậm chí tôi đã sử dụng (một phần) các thử nghiệm về sự phù hợp . Đó là một mã thông báo, không phải là trình phân tích cú pháp đầy đủ, do đó, nó sẽ chỉ phân tách XML thành các mã thông báo thành phần của nó. Nó sẽ không phân tích / tích hợp các DTD.

Ồ ... nếu bạn muốn mã nguồn của regex, với một số phương thức phụ trợ:

regex để token hóa một xml hoặc regex hoàn toàn đơn giản


68
Chúa ơi, nó thật đồ sộ. Câu hỏi lớn nhất của tôi là tại sao? Bạn nhận ra rằng tất cả các ngôn ngữ hiện đại đều có trình phân tích cú pháp XML, phải không? Bạn có thể làm tất cả những điều đó trong 3 dòng và chắc chắn nó sẽ hoạt động. Hơn nữa, bạn cũng nhận ra rằng regex thuần túy thể chứng minh là không thể làm một số điều nhất định? Trừ khi bạn đã tạo một trình phân tích cú pháp mã regex / mệnh lệnh lai, nhưng nó không giống như bạn có. Bạn có thể nén dữ liệu ngẫu nhiên không?
Justin Morgan

113
@Justin Tôi không cần một lý do. Nó có thể được thực hiện (và nó không bất hợp pháp / vô đạo đức), vì vậy tôi đã làm nó. Không có giới hạn nào cho tâm trí ngoại trừ những người chúng ta thừa nhận (Napoleon Hill) ... Các ngôn ngữ hiện đại có thể phân tích cú pháp XML? Có thật không? Và tôi nghĩ rằng đó là bất hợp pháp! :-)
xanatos

76
Thưa ông, tôi đã bị thuyết phục. Tôi sẽ sử dụng mã này như một phần của hạt nhân cho máy chuyển động vĩnh viễn của mình - bạn có thể tin những kẻ ngu ngốc đó tại văn phòng bằng sáng chế tiếp tục từ chối đơn đăng ký của tôi không? Vâng, tôi sẽ chỉ cho họ. Tôi sẽ chỉ cho tất cả!
Justin Morgan

31
@Justin Vì vậy, một Trình phân tích cú pháp Xml không có lỗi định nghĩa, trong khi Regex thì không? Bởi vì nếu định nghĩa Xml Parser không có lỗi theo định nghĩa thì có thể có một xml khiến nó bị sập và chúng tôi quay lại bước 0. Hãy nói điều này: cả Xml Parser và Regex này đều cố gắng có thể phân tích tất cả "hợp pháp "XML. Họ CÓ THỂ phân tích một số XML "bất hợp pháp". Lỗi có thể làm sập cả hai. C # XmlReader chắc chắn được thử nghiệm nhiều hơn Regex này.
xanatos

31
Không, không có gì là không có lỗi: 1) Tất cả các chương trình đều chứa ít nhất một lỗi. 2) Tất cả các chương trình chứa ít nhất một dòng mã nguồn không cần thiết. 3) Bằng # 1 và # 2 và sử dụng quy nạp logic, việc chứng minh rằng bất kỳ chương trình nào cũng có thể được giảm xuống thành một dòng mã có lỗi. (từ Learning Perl)
Scott Weaver

299

Trong shell, bạn có thể phân tích HTML bằng sed :

  1. Turing.sed
  2. Viết trình phân tích cú pháp HTML (bài tập về nhà)
  3. ???
  4. Lợi nhuận!

Liên quan (tại sao bạn không nên sử dụng kết hợp regex):


3
Tôi sợ bạn đã không nhận được trò đùa, @kenorb. Xin vui lòng, đọc câu hỏi và câu trả lời được chấp nhận một lần nữa. Đây không phải là về các công cụ phân tích cú pháp HTML nói chung, cũng không phải về các công cụ phân tích cú pháp HTML, mà là về phân tích cú pháp HTML thông qua các biểu thức chính quy.
Palec

1
Không, @Abdul. Nó là hoàn toàn, có thể chứng minh (theo nghĩa toán học) là không thể.
Palec

3
Vâng, câu trả lời đó tóm tắt nó tốt, @Abdul. Tuy nhiên, lưu ý rằng việc triển khai regex không thực sự là các biểu thức chính quy theo nghĩa toán học - chúng có các cấu trúc làm cho chúng mạnh hơn, thường là Turing-perfect (tương đương với loại 0 ngữ pháp). Cuộc tranh luận đã phá vỡ với thực tế này, nhưng vẫn có phần hợp lệ theo nghĩa là các biểu thức không bao giờ có nghĩa là có khả năng thực hiện một công việc như vậy, mặc dù.
Palec

2
Và nhân tiện, trò đùa mà tôi đề cập đến là nội dung của câu trả lời này trước khi chỉnh sửa (triệt để) của kenorb, cụ thể là phiên bản 4, @Abdul.
Palec

3
Điều buồn cười là OP không bao giờ yêu cầu phân tích html bằng regex. Ông yêu cầu khớp văn bản (có thể là HTML) bằng regex. Mà là hoàn toàn hợp lý.
Paralife

274

Tôi đồng ý rằng công cụ phù hợp để phân tích cú pháp XML và đặc biệt là HTML là một trình phân tích cú pháp chứ không phải là một công cụ biểu thức thông thường. Tuy nhiên, giống như những người khác đã chỉ ra, đôi khi sử dụng regex sẽ nhanh hơn, dễ dàng hơn và hoàn thành công việc nếu bạn biết định dạng dữ liệu.

Microsoft thực sự có một phần Thực tiễn tốt nhất cho các biểu thức chính quy trong .NET Framework và đặc biệt nói về việc xem xét [ing] Nguồn đầu vào .

Biểu thức chính quy có những hạn chế, nhưng bạn đã xem xét những điều sau đây chưa?

.NET framework là duy nhất khi nói đến các biểu thức chính quy ở chỗ nó hỗ trợ Định nghĩa nhóm cân bằng .

Vì lý do này, tôi tin rằng bạn CÓ THỂ phân tích cú pháp XML bằng các biểu thức thông thường. Tuy nhiên, xin lưu ý rằng đó phải là XML hợp lệ ( các trình duyệt rất tha thứ cho HTML và cho phép cú pháp XML xấu trong HTML ). Điều này là có thể vì "Định nghĩa nhóm cân bằng" sẽ cho phép công cụ biểu thức chính quy hoạt động như một thiết bị PDA.

Trích dẫn từ bài viết 1 trích dẫn ở trên:

.NET Công cụ biểu thức chính quy

Như mô tả ở trên, các cấu trúc cân bằng hợp lý không thể được mô tả bằng biểu thức chính quy. Tuy nhiên, công cụ biểu thức chính quy .NET cung cấp một vài cấu trúc cho phép các cấu trúc cân bằng được nhận dạng.

  • (?<group>) - đẩy kết quả đã chụp vào ngăn xếp chụp với nhóm tên.
  • (?<-group>) - bật ra phần bắt nhiều nhất với nhóm tên ngoài ngăn xếp.
  • (?(group)yes|no) - khớp với phần có nếu tồn tại một nhóm với nhóm tên khác không khớp với phần đó.

Các cấu trúc này cho phép một biểu thức chính quy .NET mô phỏng một thiết bị bị hạn chế bằng cách cho phép các phiên bản đơn giản của các hoạt động ngăn xếp: đẩy, bật và trống. Các hoạt động đơn giản là khá nhiều tương đương với tăng, giảm và so sánh với không tương ứng. Điều này cho phép công cụ biểu thức chính quy .NET nhận ra một tập hợp con của các ngôn ngữ không ngữ cảnh, đặc biệt là các ngôn ngữ chỉ yêu cầu một bộ đếm đơn giản. Điều này đến lượt nó cho phép các biểu thức chính quy .NET không truyền thống nhận ra các cấu trúc cân bằng riêng lẻ.

Hãy xem xét các biểu thức chính quy sau:

(?=<ul\s+id="matchMe"\s+type="square"\s*>)
(?>
   <!-- .*? -->                  |
   <[^>]*/>                      |
   (?<opentag><(?!/)[^>]*[^/]>)  |
   (?<-opentag></[^>]*[^/]>)     |
   [^<>]*
)*
(?(opentag)(?!))

Sử dụng các cờ:

  • Đường đơn
  • IgnorePotypeWhitespace (không cần thiết nếu bạn thu gọn regex và xóa tất cả khoảng trắng)
  • IgnoreCase (không cần thiết)

Giải thích biểu thức chính quy (nội tuyến)

(?=<ul\s+id="matchMe"\s+type="square"\s*>) # match start with <ul id="matchMe"...
(?>                                        # atomic group / don't backtrack (faster)
   <!-- .*? -->                 |          # match xml / html comment
   <[^>]*/>                     |          # self closing tag
   (?<opentag><(?!/)[^>]*[^/]>) |          # push opening xml tag
   (?<-opentag></[^>]*[^/]>)    |          # pop closing xml tag
   [^<>]*                                  # something between tags
)*                                         # match as many xml tags as possible
(?(opentag)(?!))                           # ensure no 'opentag' groups are on stack

Bạn có thể thử điều này tại Trình kiểm tra biểu thức chính quy .NET tốt hơn .

Tôi đã sử dụng nguồn mẫu của:

<html>
<body>
<div>
   <br />
   <ul id="matchMe" type="square">
      <li>stuff...</li>
      <li>more stuff</li>
      <li>
          <div>
               <span>still more</span>
               <ul>
                    <li>Another &gt;ul&lt;, oh my!</li>
                    <li>...</li>
               </ul>
          </div>
      </li>
   </ul>
</div>
</body>
</html>

Điều này tìm thấy sự phù hợp:

   <ul id="matchMe" type="square">
      <li>stuff...</li>
      <li>more stuff</li>
      <li>
          <div>
               <span>still more</span>
               <ul>
                    <li>Another &gt;ul&lt;, oh my!</li>
                    <li>...</li>
               </ul>
          </div>
      </li>
   </ul>

mặc dù nó thực sự xuất hiện như thế này:

<ul id="matchMe" type="square">           <li>stuff...</li>           <li>more stuff</li>           <li>               <div>                    <span>still more</span>                    <ul>                         <li>Another &gt;ul&lt;, oh my!</li>                         <li>...</li>                    </ul>               </div>           </li>        </ul>

Cuối cùng, tôi thực sự thích bài viết của Jeff Atwood: Phân tích cú pháp Html Cách Cthulhu . Hài hước lắm, nó trích dẫn câu trả lời cho câu hỏi này hiện có hơn 4k phiếu bầu.


18
System.Textkhông phải là một phần của C #. Đây là một phần của .NET.
John Saunders

8
Trong dòng đầu tiên của regex của bạn ( (?=<ul\s*id="matchMe"\s*type="square"\s*>) # match start with <ul id="matchMe"...), ở giữa "<ul" và "id" nên \s+, không \s*, trừ khi bạn muốn nó khớp với <ulid = ...;)
C0deH4cker

@ C0deH4cker Bạn đã đúng, biểu thức nên có \s+thay vì \s*.
Sam

4
Không phải là tôi thực sự hiểu nó, nhưng tôi nghĩ rằng regex của bạn thất bại vào<img src="images/pic.jpg" />
Scheintod

3
@Scheintod Cảm ơn bạn đã bình luận. Tôi đã cập nhật mã. Biểu thức trước đó không thành công cho các thẻ tự đóng có một /nơi nào đó bên trong không thành công cho <img src="images/pic.jpg" />html của bạn .
Sam

258

Tôi đề nghị sử dụng QueryPath để phân tích cú pháp XML và HTML trong PHP. Về cơ bản, nó rất giống cú pháp với jQuery, chỉ có ở phía máy chủ.


8
@ Kyle Tiết jQuery không phân tích cú pháp XML, nó sử dụng chương trình phân tích cú pháp được xây dựng của máy khách (nếu có). Do đó, bạn không cần jQuery để làm điều đó, nhưng chỉ bằng hai dòng JavaScript cũ đơn giản . Nếu không có chương trình xây dựng trong trình phân tích cú pháp, jQuery sẽ không giúp đỡ.
RobG

1
@RobG Trên thực tế jQuery sử dụng DOM, không phải trình phân tích cú pháp tích hợp.
Qix - MONICA ĐƯỢC PHÂN PHỐI

11
@ Qix, bạn nên nói với các tác giả của tài liệu sau đó: " jQuery.parseXML sử dụng chức năng phân tích cú pháp riêng của trình duyệt. " Nguồn: jQuery.parseXML ()
RobG

6
Đã đến đây từ câu hỏi meme ( meta.stackexchange.com/questions/19478/the-many-meme-of-meta/ trộm ), tôi thích rằng một trong những câu trả lời là 'Sử dụng jQuery'
Jorn

221

Mặc dù các câu trả lời mà bạn không thể phân tích HTML bằng regexes là chính xác, nhưng chúng không áp dụng ở đây. OP chỉ muốn phân tích một thẻ HTML bằng các biểu thức chính quy và đó là điều có thể được thực hiện với một biểu thức thông thường.

Regex được đề xuất là sai, mặc dù:

<([a-z]+) *[^/]*?>

Nếu bạn thêm một cái gì đó vào regex, bằng cách quay lại, nó có thể bị buộc phải khớp với những thứ ngớ ngẩn như <a >>, [^/]quá dễ dãi. Cũng lưu ý rằng <space>*[^/]*là dư thừa, bởi vì [^/]*cũng có thể phù hợp với không gian.

Đề nghị của tôi sẽ là

<([a-z]+)[^>]*(?<!/)>

Đâu (?<! ... )là (trong Perl regexes) cái nhìn tiêu cực phía sau. Nó đọc "a <, sau đó là một từ, sau đó bất cứ thứ gì không phải là>, cuối cùng có thể không phải là /, theo sau là" ".

Lưu ý rằng điều này cho phép những thứ như <a/ >(giống như regex ban đầu), vì vậy nếu bạn muốn một cái gì đó hạn chế hơn, bạn cần xây dựng một regex để khớp các cặp thuộc tính được phân tách bằng dấu cách.


29
+1 để lưu ý rằng câu hỏi không phải là về phân tích cú pháp HTML đầy đủ (X), mà là về các thẻ mở HTML phù hợp (X).
LarsH

10
Một điều khác mà hầu hết các câu trả lời dường như bỏ qua, đó là trình phân tích cú pháp HTML rất có thể sử dụng các biểu thức chính quy để triển khai cho các phần của HTML và tôi sẽ ngạc nhiên nếu hầu hết các trình phân tích cú pháp không làm điều này.
Thayne

@Thayne Chính xác. Khi phân tích cú pháp các thẻ riêng lẻ, một biểu thức chính quy là công cụ phù hợp cho công việc. Một điều khá nực cười là người ta phải cuộn nửa trang để tìm câu trả lời hợp lý. Câu trả lời được chấp nhận là không chính xác vì nó trộn lẫn giữa lexing và phân tích cú pháp.
kasperd

2
Câu trả lời được đưa ra ở đây sẽ thất bại khi một giá trị thuộc tính chứa ký tự '>' hoặc '/'.
Martin L

Điều này sẽ hoạt động không chính xác trên HTML có chứa các bình luận hoặc phần CData. Nó cũng sẽ không hoạt động chính xác nếu một thuộc tính được trích dẫn có chứa một >ký tự. Tôi đồng ý những gì OP đề xuất có thể được thực hiện với regex, nhưng cách trình bày ở đây rất đơn giản.
JacquesB

183

Thử:

<([^\s]+)(\s[^>]*?)?(?<!/)>

Nó tương tự như của bạn, nhưng cuối cùng >không được sau một dấu gạch chéo, và cũng chấp nhận h1.


107
<a href="foo" title="5> 3 "> Rất tiếc </a>
Gareth

21
Điều đó rất đúng và tôi đã nghĩ về nó, nhưng tôi cho rằng >biểu tượng được thoát đúng cách thành & gt;.
Kobi

65
>là hợp lệ trong một giá trị thuộc tính. Thật vậy, trong tuần tự hóa 'XML chuẩn', bạn không được sử dụng &gt;. (Điều này hoàn toàn không liên quan, ngoại trừ việc nhấn mạnh rằng >trong một giá trị thuộc tính hoàn toàn không phải là một điều bất thường.)
bobince

5
@Kobi: dấu exlamation (cái bạn đặt tpward the end) nghĩa là gì trong một biểu thức chính quy?
Marco Demaio

6
@bobince: bạn có chắc không? Tôi không hiểu nữa, HTML này cũng hợp lệ:<div title="this tag is a <div></div>">hello</div>
Marco Demaio

179

Tôn Tử, một chiến lược gia, tướng quân, và triết gia cổ đại của Trung Quốc, đã nói:

Người ta nói rằng nếu bạn biết kẻ thù của mình và biết chính mình, bạn có thể chiến thắng một trăm trận chiến mà không mất một lần nào. Nếu bạn chỉ biết bản thân mình, nhưng không phải đối thủ của bạn, bạn có thể thắng hoặc có thể thua. Nếu bạn không biết chính mình cũng không phải kẻ thù, bạn sẽ luôn gây nguy hiểm cho chính mình.

Trong trường hợp này, kẻ thù của bạn là HTML và bạn là chính bạn hoặc regex. Bạn thậm chí có thể là Perl với regex bất thường. Biết HTML. Biết chính mình.

Tôi đã sáng tác một bài haiku mô tả bản chất của HTML.

HTML has
complexity exceeding
regular language.

Tôi cũng đã sáng tác một bài haiku mô tả bản chất của regex trong Perl.

The regex you seek
is defined within the phrase
<([a-zA-Z]+)(?:[^>]*[^/]*)?>

153
<?php
$selfClosing = explode(',', 'area,base,basefont,br,col,frame,hr,img,input,isindex,link,meta,param,embed');

$html = '
<p><a href="#">foo</a></p>
<hr/>
<br/>
<div>name</div>';

$dom = new DOMDocument();
$dom->loadHTML($html);
$els = $dom->getElementsByTagName('*');
foreach ( $els as $el ) {
    $nodeName = strtolower($el->nodeName);
    if ( !in_array( $nodeName, $selfClosing ) ) {
        var_dump( $nodeName );
    }
}

Đầu ra:

string(4) "html"
string(4) "body"
string(1) "p"
string(1) "a"
string(3) "div"

Về cơ bản chỉ cần xác định các tên nút phần tử tự đóng, tải toàn bộ chuỗi html vào thư viện DOM, lấy tất cả các phần tử, lặp qua và lọc ra các tên không tự đóng và hoạt động trên chúng.

Tôi chắc chắn bạn đã biết rằng bạn không nên sử dụng regex cho mục đích này.


1
Nếu bạn đang làm việc với XHTML thực thì hãy thêm getElementsByTagName với NSvà chỉ định không gian tên.
meder omuraliev

148

Tôi không biết chính xác nhu cầu của bạn cho việc này, nhưng nếu bạn cũng đang sử dụng .NET, bạn có thể sử dụng Gói Agility Agml không?

Trích đoạn:

Đây là một thư viện mã .NET cho phép bạn phân tích các tệp HTML "ra khỏi web". Trình phân tích cú pháp rất khoan dung với HTML không đúng định dạng "thế giới thực".


137

Bạn muốn đầu tiên >không đi trước a /. Nhìn vào đây để biết chi tiết về cách làm điều đó. Nó được gọi là cái nhìn tiêu cực.

Tuy nhiên, việc triển khai ngây thơ sẽ kết thúc khớp <bar/></foo>trong tài liệu ví dụ này

<foo><bar/></foo>

Bạn có thể cung cấp thêm một chút thông tin về vấn đề bạn đang cố gắng giải quyết không? Bạn đang lặp qua các thẻ theo chương trình?


1
Đúng, tôi chắc chắn. Xác định tất cả các thẻ hiện đang mở, sau đó so sánh với các thẻ đã đóng trong một mảng riêng. RegEx làm tổn thương não của tôi.
Jeff

122

W3C giải thích phân tích cú pháp theo hình thức regrec giả:
Liên kết W3C

Thực hiện theo các liên kết var cho QName, SAttributeđể có được một bức tranh rõ ràng hơn.
Dựa vào đó, bạn có thể tạo một biểu thức chính quy khá tốt để xử lý những thứ như tước thẻ.


5
Đó không phải là biểu mẫu regrec psuedo, đó là biểu mẫu EBNF, như được chỉ định ở đây: thông số XML, phụ lục 6
Rob G

106

Nếu bạn cần điều này cho PHP:

Các hàm PHP DOM sẽ không hoạt động đúng trừ khi nó được định dạng đúng XML. Không có vấn đề sử dụng tốt hơn cho phần còn lại của nhân loại.

đơn giản là tốt, nhưng tôi thấy nó có một chút lỗi và nó khá nặng bộ nhớ [Sẽ sụp đổ trên các trang lớn.]

Tôi chưa bao giờ sử dụng querypath , vì vậy không thể nhận xét về tính hữu ích của nó.

Một cái khác để thử là DOMParser của tôi rất nhẹ về tài nguyên và tôi đã sử dụng một cách vui vẻ trong một thời gian. Đơn giản để học & mạnh mẽ.

Đối với Python và Java, các liên kết tương tự đã được đăng.

Đối với các downvoters - Tôi chỉ viết lớp của mình khi các trình phân tích cú pháp XML tỏ ra không thể chịu được việc sử dụng thực sự. Việc hạ thấp tôn giáo chỉ ngăn chặn những câu trả lời hữu ích được đăng lên - làm ơn giữ mọi thứ trong tầm nhìn của câu hỏi.


95

Đây là giải pháp:

<?php
// here's the pattern:
$pattern = '/<(\w+)(\s+(\w+)\s*\=\s*(\'|")(.*?)\\4\s*)*\s*(\/>|>)/';

// a string to parse:
$string = 'Hello, try clicking <a href="#paragraph">here</a>
    <br/>and check out.<hr />
    <h2>title</h2>
    <a name ="paragraph" rel= "I\'m an anchor"></a>
    Fine, <span title=\'highlight the "punch"\'>thanks<span>.
    <div class = "clear"></div>
    <br>';

// let's get the occurrences:
preg_match_all($pattern, $string, $matches, PREG_PATTERN_ORDER);

// print the result:
print_r($matches[0]);
?>

Để kiểm tra sâu, tôi đã nhập vào các thẻ tự động đóng chuỗi như:

  1. <giờ />
  2. <br/>
  3. <br>

Tôi cũng đã nhập các thẻ với:

  1. một thuộc tính
  2. nhiều hơn một thuộc tính
  3. các thuộc tính có giá trị được ràng buộc vào dấu ngoặc đơn hoặc dấu ngoặc kép
  4. thuộc tính chứa dấu ngoặc đơn khi dấu phân cách là dấu ngoặc kép và ngược lại
  5. Thuộc tính "không chính xác" có khoảng trắng trước biểu tượng "=", sau nó và cả trước và sau nó.

Nếu bạn tìm thấy một cái gì đó không hoạt động trong bằng chứng về khái niệm ở trên, tôi có sẵn trong việc phân tích mã để cải thiện kỹ năng của tôi.

<EDIT> Tôi quên rằng câu hỏi từ người dùng là để tránh phân tích cú pháp các thẻ tự đóng. Trong trường hợp này, mẫu đơn giản hơn, biến thành thế này:

$pattern = '/<(\w+)(\s+(\w+)\s*\=\s*(\'|")(.*?)\\4\s*)*\s*>/';

Người dùng @ridgerunner nhận thấy rằng mẫu không cho phép các thuộc tính hoặc thuộc tính không được trích dẫn không có giá trị . Trong trường hợp này, một tinh chỉnh mang lại cho chúng ta mẫu sau:

$pattern = '/<(\w+)(\s+(\w+)(\s*\=\s*(\'|"|)(.*?)\\5\s*)?)*\s*>/';

</ CHỈNH SỬA>

Hiểu mô hình

Nếu ai đó quan tâm đến việc tìm hiểu thêm về mẫu, tôi cung cấp một số dòng:

  1. biểu thức con đầu tiên (\ w +) khớp với tên thẻ
  2. biểu thức con thứ hai chứa mẫu của một thuộc tính. Nó được sáng tác bởi:
    1. một hoặc nhiều khoảng trắng \ s +
    2. tên của thuộc tính (\ w +)
    3. không hoặc nhiều khoảng trắng \ s * (có thể hoặc không, để trống ở đây)
    4. biểu tượng "="
    5. một lần nữa, không hoặc nhiều khoảng trắng
    6. dấu phân cách của giá trị thuộc tính, một trích dẫn đơn hoặc kép ('| "). Trong mẫu, trích dẫn đơn được thoát vì nó trùng với dấu phân cách chuỗi PHP. Biểu thức phụ này được ghi lại bằng dấu ngoặc đơn để có thể được tham chiếu một lần nữa để phân tích việc đóng thuộc tính, đó là lý do tại sao nó rất quan trọng.
    7. giá trị của thuộc tính, khớp với hầu hết mọi thứ: (. *?); trong cú pháp cụ thể này, bằng cách sử dụng kết hợp tham lam (dấu hỏi sau dấu hoa thị), công cụ RegExp cho phép toán tử giống như "nhìn về phía trước", khớp với bất kỳ thứ gì ngoại trừ biểu thức phụ này
    8. ở đây có một điều thú vị: phần \ 4 là toán tử phản xạ , đề cập đến một biểu thức con được xác định trước trong mẫu, trong trường hợp này, tôi đang đề cập đến biểu thức phụ thứ tư, là dấu phân cách thuộc tính đầu tiên được tìm thấy
    9. không hoặc nhiều khoảng trắng \ s *
    10. biểu thức phụ thuộc tính kết thúc ở đây, với đặc điểm kỹ thuật bằng 0 hoặc nhiều lần xuất hiện hơn, được đưa ra bởi dấu hoa thị.
  3. Sau đó, vì thẻ có thể kết thúc bằng khoảng trắng trước biểu tượng ">", không hoặc nhiều khoảng trắng được khớp với mẫu con \ s *.
  4. Thẻ để khớp có thể kết thúc bằng ký hiệu ">" đơn giản hoặc đóng XHTML có thể, sử dụng dấu gạch chéo trước nó: (/> |>). Dấu gạch chéo, tất nhiên, đã thoát vì nó trùng với dấu phân cách biểu thức chính quy.

Mẹo nhỏ: để phân tích tốt hơn mã này, cần phải xem mã nguồn được tạo vì tôi không cung cấp bất kỳ ký tự đặc biệt HTML nào thoát.


12
Không khớp với các thẻ hợp lệ có thuộc tính không có giá trị, nghĩa là <option selected>. Cũng không khớp các thẻ hợp lệ với các giá trị thuộc tính không được trích dẫn, nghĩa là <p id=10>.
Ridgerunner

1
@ridgerunner: Cảm ơn rất nhiều vì bình luận của bạn. Trong trường hợp đó, mẫu phải thay đổi một chút: $ pattern = '/ <(\ w +) (\ s + (\ w +) (\ s * \ = \ s * (\' | "|) (. *?) \\ 5 \ s *)?) * \ S *> / '; Tôi đã thử nghiệm nó và hoạt động trong trường hợp thuộc tính hoặc thuộc tính không được trích dẫn không có giá trị.
Emanuele Del Grande

Làm thế nào về một khoảng trắng trước tên thẻ: < a href="http://wtf.org" >Tôi khá chắc chắn rằng đó là hợp pháp, nhưng bạn không khớp với nó.
Floris

7
KHÔNG xin lỗi, khoảng trắng trước khi tagname là bất hợp pháp. Ngoài việc "khá chắc chắn" tại sao bạn không cung cấp một số bằng chứng về sự phản đối của bạn? Đây là của tôi, w3.org/TR/xml11/#sec-starttags được đề cập đến XML 1.1 và bạn có thể tìm thấy điều tương tự cho HTML 4, 5 và XHTML, vì xác thực W3C cũng sẽ cảnh báo nếu bạn thực hiện kiểm tra. Như nhiều nhà thơ blah-blah khác ở đây, tôi vẫn không nhận được bất kỳ lý lẽ thông minh nào, ngoài hàng trăm câu trả lời cho câu trả lời của tôi, để chứng minh mã của tôi thất bại theo quy tắc hợp đồng được chỉ định trong câu hỏi. Tôi chỉ chào đón họ.
Emanuele Del Grande

@ridgerunner tất nhiên nhận xét của bạn rất thông minh và được chào đón.
Emanuele Del Grande

91

Bất cứ khi nào tôi cần nhanh chóng trích xuất thứ gì đó từ tài liệu HTML, tôi sử dụng Tidy để chuyển đổi nó thành XML và sau đó sử dụng XPath hoặc XSLT để có được thứ tôi cần. Trong trường hợp của bạn, một cái gì đó như thế này:

//p/a[@href='foo']

89

Tôi đã sử dụng một công cụ nguồn mở được gọi là HTMLParser trước đây. Nó được thiết kế để phân tích HTML theo nhiều cách khác nhau và phục vụ mục đích khá tốt. Nó có thể phân tích HTML dưới dạng treenode khác nhau và bạn có thể dễ dàng sử dụng API của nó để lấy các thuộc tính ra khỏi nút. Kiểm tra nó và xem nếu điều này có thể giúp bạn.


84

Tôi thích phân tích HTML bằng các biểu thức thông thường. Tôi không cố phân tích HTML ngu ngốc bị phá vỡ có chủ ý. Mã này là trình phân tích cú pháp chính của tôi (phiên bản Perl):

$_ = join "",<STDIN>; tr/\n\r \t/ /s; s/</\n</g; s/>/>\n/g; s/\n ?\n/\n/g;
s/^ ?\n//s; s/ $//s; print

Nó được gọi là htmlsplit, chia HTML thành các dòng, với một thẻ hoặc đoạn văn bản trên mỗi dòng. Các dòng sau đó có thể được xử lý thêm bằng các công cụ văn bản và tập lệnh khác, chẳng hạn như grep , sed , Perl, v.v. Tôi thậm chí không nói đùa :) Thưởng thức.

Nó đủ đơn giản để chuyển đổi tập lệnh Perl đầu tiên của tôi thành một thứ phát trực tuyến tốt, nếu bạn muốn xử lý các trang web khổng lồ. Nhưng nó không thực sự cần thiết.

Tôi cá là tôi sẽ bị hạ bệ vì điều này.

Chia HTML


Chống lại sự mong đợi của tôi, điều này có một số upvote, vì vậy tôi sẽ đề xuất một số biểu thức chính quy tốt hơn:

/(<.*?>|[^<]+)\s*/g    # get tags and text
/(\w+)="(.*?)"/g       # get attibutes

Chúng tốt cho XML / XHTML.

Với các biến thể nhỏ, nó có thể đối phó với HTML lộn xộn ... hoặc chuyển đổi HTML -> XHTML trước.


Cách tốt nhất để viết các biểu thức chính quy là theo kiểu Lex / Yacc , không phải là các dòng một dòng mờ đục hoặc nhận xét về sự quái dị nhiều dòng. Tôi đã không làm điều đó ở đây, chưa; những cái này hầu như không cần nó


35
"Tôi không cố phân tích HTML ngu ngốc bị phá vỡ có chủ ý." Làm thế nào để mã của bạn biết sự khác biệt?
Kevin Panko

Chà nó không quan trọng lắm nếu HTML bị hỏng hay không. Điều này vẫn sẽ chia HTML thành các thẻ và văn bản. Điều duy nhất có thể làm hỏng nó là nếu mọi người bao gồm các ký tự <hoặc> không được giải mã trong văn bản hoặc thuộc tính. Trong thực tế, bộ chia HTML nhỏ của tôi hoạt động tốt. Tôi không cần một sự quái dị to lớn đầy ắp những heuristic. Giải pháp đơn giản không dành cho tất cả mọi người ...!
Sam Watkins

Tôi đã thêm một số biểu thức chính đơn giản hơn để trích xuất thẻ, văn bản và thuộc tính cho XML / XHTML.
Sam Watkins

(nhận lỗi thuộc tính 1) /(\w+)="(.*?)"/giả sử dấu ngoặc kép. Nó sẽ bỏ lỡ các giá trị trong dấu ngoặc đơn. Trong phiên bản html 4 và giá trị không trích dẫn trước đó được cho phép, nếu đó là một từ đơn giản.
David Andersson

(get thuộc tính lỗi 2) /(\w+)="(.*?)"/có thể sai phù hợp với văn bản mà trông giống như một thuộc tính trong vòng một thuộc tính, ví dụ <img title="Nope down='up' for aussies" src="..." />. Nếu được áp dụng trên toàn cầu, nó cũng sẽ khớp những thứ như vậy trong văn bản thông thường hoặc trong các bình luận html.
David Andersson

74

Đây là một trình phân tích cú pháp dựa trên PHP để phân tích cú pháp HTML bằng cách sử dụng một số biểu thức chính quy vô duyên. Là tác giả của dự án này, tôi có thể nói với bạn rằng có thể phân tích HTML bằng regex, nhưng không hiệu quả. Nếu bạn cần một giải pháp phía máy chủ (như tôi đã làm cho plugin wp-typography WordPress của tôi ), thì nó hoạt động.


1
htmlawed là một dự án PHP khác phân tích HTML để lọc, chuyển đổi, v.v. Có một số mã hay nếu bạn có thể tìm ra nó!
dùng594694

Không, bạn không thể phân tích HTML bằng regex. Nhưng đối với một số tập con, nó có thể hoạt động.
mirabilos

71

Có một số biểu thức chính để thay thế HTML bằng BBCode tại đây . Đối với tất cả những người bạn nói, lưu ý rằng anh ta không cố gắng phân tích hoàn toàn HTML, chỉ để vệ sinh nó. Anh ta có thể đủ khả năng để tiêu diệt các thẻ mà "trình phân tích cú pháp" đơn giản của anh ta không thể hiểu được.

Ví dụ:

$store =~ s/http:/http:\/\//gi;
$store =~ s/https:/https:\/\//gi;
$baseurl = $store;

if (!$query->param("ascii")) {
    $html =~ s/\s\s+/\n/gi;
    $html =~ s/<pre(.*?)>(.*?)<\/pre>/\[code]$2\[\/code]/sgmi;
}

$html =~ s/\n//gi;
$html =~ s/\r\r//gi;
$html =~ s/$baseurl//gi;
$html =~ s/<h[1-7](.*?)>(.*?)<\/h[1-7]>/\n\[b]$2\[\/b]\n/sgmi;
$html =~ s/<p>/\n\n/gi;
$html =~ s/<br(.*?)>/\n/gi;
$html =~ s/<textarea(.*?)>(.*?)<\/textarea>/\[code]$2\[\/code]/sgmi;
$html =~ s/<b>(.*?)<\/b>/\[b]$1\[\/b]/gi;
$html =~ s/<i>(.*?)<\/i>/\[i]$1\[\/i]/gi;
$html =~ s/<u>(.*?)<\/u>/\[u]$1\[\/u]/gi;
$html =~ s/<em>(.*?)<\/em>/\[i]$1\[\/i]/gi;
$html =~ s/<strong>(.*?)<\/strong>/\[b]$1\[\/b]/gi;
$html =~ s/<cite>(.*?)<\/cite>/\[i]$1\[\/i]/gi;
$html =~ s/<font color="(.*?)">(.*?)<\/font>/\[color=$1]$2\[\/color]/sgmi;
$html =~ s/<font color=(.*?)>(.*?)<\/font>/\[color=$1]$2\[\/color]/sgmi;
$html =~ s/<link(.*?)>//gi;
$html =~ s/<li(.*?)>(.*?)<\/li>/\[\*]$2/gi;
$html =~ s/<ul(.*?)>/\[list]/gi;
$html =~ s/<\/ul>/\[\/list]/gi;
$html =~ s/<div>/\n/gi;
$html =~ s/<\/div>/\n/gi;
$html =~ s/<td(.*?)>/ /gi;
$html =~ s/<tr(.*?)>/\n/gi;

$html =~ s/<img(.*?)src="(.*?)"(.*?)>/\[img]$baseurl\/$2\[\/img]/gi;
$html =~ s/<a(.*?)href="(.*?)"(.*?)>(.*?)<\/a>/\[url=$baseurl\/$2]$4\[\/url]/gi;
$html =~ s/\[url=$baseurl\/http:\/\/(.*?)](.*?)\[\/url]/\[url=http:\/\/$1]$2\[\/url]/gi;
$html =~ s/\[img]$baseurl\/http:\/\/(.*?)\[\/img]/\[img]http:\/\/$1\[\/img]/gi;

$html =~ s/<head>(.*?)<\/head>//sgmi;
$html =~ s/<object>(.*?)<\/object>//sgmi;
$html =~ s/<script(.*?)>(.*?)<\/script>//sgmi;
$html =~ s/<style(.*?)>(.*?)<\/style>//sgmi;
$html =~ s/<title>(.*?)<\/title>//sgmi;
$html =~ s/<!--(.*?)-->/\n/sgmi;

$html =~ s/\/\//\//gi;
$html =~ s/http:\//http:\/\//gi;
$html =~ s/https:\//https:\/\//gi;

$html =~ s/<(?:[^>'"]*|(['"]).*?\1)*>//gsi;
$html =~ s/\r\r//gi;
$html =~ s/\[img]\//\[img]/gi;
$html =~ s/\[url=\//\[url=/gi;

15
Đừng làm điều này. Xin vui lòng.
maletor

68

Về câu hỏi về các phương pháp RegExp để phân tích (x) HTML, câu trả lời cho tất cả những người đã nói về một số giới hạn là: bạn chưa được đào tạo đủ để cai trị lực lượng của vũ khí mạnh mẽ này, vì NOBODY ở đây đã nói về đệ quy .

Một đồng nghiệp của RegExp-agnellect đã thông báo cho tôi cuộc thảo luận này, đây không phải là lần đầu tiên trên web về chủ đề cũ và nóng này.

Sau khi đọc một số bài viết, điều đầu tiên tôi làm là tìm kiếm chuỗi "? R" trong chuỗi này. Thứ hai là tìm kiếm về "đệ quy".
Không, bò thần, không tìm thấy trận đấu.
Vì không ai đề cập đến cơ chế chính mà trình phân tích cú pháp được xây dựng, tôi đã sớm nhận ra rằng không ai có được điểm này.

Nếu trình phân tích cú pháp HTML (x) cần đệ quy, trình phân tích cú pháp RegExp không có đệ quy là không đủ cho mục đích. Đó là một cấu trúc đơn giản.

Các nghệ thuật đen của RegExp rất khó để làm chủ , như vậy có lẽ có khả năng hơn nữa chúng tôi rời ra trong khi cố gắng và thử nghiệm giải pháp cá nhân của chúng tôi để chụp toàn bộ trang web trong một bàn tay ... Vâng, tôi chắc chắn về điều đó :)

Đây là mô hình kỳ diệu:

$pattern = "/<([\w]+)([^>]*?)(([\s]*\/>)|(>((([^<]*?|<\!\-\-.*?\-\->)|(?R))*)<\/\\1[\s]*>))/s";

Hãy thử nó.
Nó được viết dưới dạng một chuỗi PHP, vì vậy công cụ sửa đổi "s" làm cho các lớp bao gồm các dòng mới.
Đây là một ghi chú mẫu trong hướng dẫn sử dụng PHP tôi đã viết vào tháng 1: Tham khảo

(Hãy cẩn thận, trong lưu ý đó, tôi đã sử dụng sai công cụ sửa đổi "m"; nó nên bị xóa, mặc dù nó bị loại bỏ bởi công cụ RegExp, vì không sử dụng ^ hoặc $ neo).

Bây giờ, chúng ta có thể nói về các giới hạn của phương pháp này từ quan điểm thông tin hơn:

  1. theo cách triển khai cụ thể của công cụ RegExp, đệ quy có thể có giới hạn về số lượng các mẫu lồng nhau được phân tích cú pháp , nhưng nó phụ thuộc vào ngôn ngữ được sử dụng
  2. Mặc dù HTML (x) bị hỏng không dẫn đến các lỗi nghiêm trọng, nhưng nó không được khử trùng .

Dù sao nó chỉ là một mẫu RegExp, nhưng nó tiết lộ khả năng phát triển rất nhiều triển khai mạnh mẽ.
Tôi đã viết mẫu này để cung cấp năng lượng cho trình phân tích cú pháp gốc đệ quy của công cụ mẫu mà tôi đã xây dựng trong khung của mình và các hiệu suất thực sự tuyệt vời, cả về thời gian thực hiện hoặc sử dụng bộ nhớ (không liên quan gì đến các công cụ mẫu khác sử dụng cùng một cú pháp).


35
Tôi sẽ đặt cái này vào thùng "Regex không cho phép lớn hơn trong thuộc tính". Kiểm tra nó với <input value = "là 5> 3?" />
Gareth

68
Nếu bạn đặt một cái gì đó như thế trong mã sản xuất, bạn có thể sẽ bị người bảo trì bắn. Một bồi thẩm đoàn sẽ không bao giờ kết án anh ta.
aehiilrs

30
Biểu thức thông thường không thể hoạt động vì theo định nghĩa chúng không được đệ quy. Việc thêm một toán tử đệ quy vào các biểu thức chính quy về cơ bản tạo ra một CFG chỉ với cú pháp kém hơn. Tại sao không sử dụng một cái gì đó được thiết kế để đệ quy ở nơi đầu tiên thay vì chèn dữ liệu đệ quy vào một cái gì đó đã tràn ngập chức năng bên ngoài?
Welbog

16
Phản đối của tôi không phải là một trong những chức năng mà nó là một trong những thời gian đầu tư. Vấn đề với RegEx là vào thời điểm bạn đăng một lớp lót nhỏ gọn, có vẻ như bạn đã làm một cái gì đó hiệu quả hơn ("Xem một dòng mã!"). Và tất nhiên không ai đề cập đến nửa giờ (hoặc 3) mà họ đã dành cho cheat-sheet của họ và (hy vọng) kiểm tra mọi hoán vị có thể có của đầu vào. Và một khi bạn vượt qua tất cả những điều đó khi người bảo trì tìm ra hoặc xác nhận mã họ không thể chỉ nhìn vào nó và thấy rằng nó đúng. Phải mổ xẻ biểu thức và về cơ bản kiểm tra lại nó một lần nữa ...
Oorang

15
... Để biết rằng nó là tốt. Và điều đó sẽ xảy ra ngay cả với những người tốt với regex. Và thành thật mà nói tôi nghi ngờ rằng phần lớn mọi người sẽ không biết rõ về nó. Vì vậy, bạn có một trong những cơn ác mộng bảo trì khét tiếng nhất và kết hợp nó với đệ quy là cơn ác mộng bảo trì khác và tôi nghĩ rằng bản thân tôi thực sự cần trong dự án của mình là một người kém thông minh hơn một chút. Mục tiêu là viết mã mà các lập trình viên xấu có thể duy trì mà không phá vỡ cơ sở mã. Tôi biết nó có mã hóa cho mẫu số ít phổ biến nhất. Nhưng tuyển dụng tài năng xuất sắc rất khó, và bạn thường ...
Oorang

62

Như nhiều người đã chỉ ra, HTML không phải là một ngôn ngữ thông thường có thể gây khó khăn cho việc phân tích cú pháp. Giải pháp của tôi cho vấn đề này là biến nó thành ngôn ngữ thông thường bằng chương trình gọn gàng và sau đó sử dụng trình phân tích cú pháp XML để sử dụng kết quả. Có rất nhiều lựa chọn tốt cho việc này. Chương trình của tôi được viết bằng Java với thư viện jtidy để biến HTML thành XML và sau đó Jaxen thành xpath thành kết quả.


61
<\s*(\w+)[^/>]*>

Các phần giải thích:

<: nhân vật bắt đầu

\s*: nó có thể có khoảng trắng trước tên thẻ (xấu nhưng có thể).

(\w+): thẻ có thể chứa chữ cái và số (h1). Chà, \wcũng khớp với '_', nhưng tôi đoán nó không đau. Nếu tò mò sử dụng ([a-zA-Z0-9] +) thay vào đó.

[^/>]*: bất cứ điều gì ngoại trừ >/cho đến khi đóng cửa>

>: đóng cửa >

KHÔNG GIỚI HẠN

Và với những người đánh giá thấp những biểu hiện thông thường nói rằng họ chỉ mạnh mẽ như các ngôn ngữ thông thường:

a n ba n ba n không thường xuyên và thậm chí không có ngữ cảnh, có thể được khớp với^(a+)b\1b\1$

Phản hồi FTW !


@GlitchMr, đó là quan điểm của anh ấy. Biểu thức chính quy hiện đại không phải là kỹ thuật thường xuyên, cũng không có lý do nào cho chúng.
alanaktion

3
@alanaktion: Các biểu thức chính quy "hiện đại" (đọc: với phần mở rộng Perl) không thể khớp trong O(MN)(M là độ dài biểu thức chính quy, N là độ dài văn bản). Backreferences là một trong những nguyên nhân của điều đó. Việc thực hiện trong awk không có phản hồi và phù hợp với mọi thứ trong O(MN)thời gian.
Konrad Borowski

56

Nếu bạn chỉ đơn giản là cố gắng tìm các thẻ đó (không có tham vọng phân tích cú pháp), hãy thử biểu thức chính quy này:

/<[^/]*?>/g

Tôi đã viết nó trong 30 giây và thử nghiệm tại đây: http://gskinner.com/RegExr/

Nó phù hợp với các loại thẻ bạn đã đề cập, trong khi bỏ qua các loại bạn nói bạn muốn bỏ qua.


2
Tôi nghĩ bạn có nghĩa là \/>thay vì \\>.
Justin Morgan

Không, chỉ \>là những gì tôi muốn nói; Tôi không bao giờ có ý định chỉnh sửa biểu thức chính quy của bài viết gốc của tôi.
Lonnie hay nhất

2
FYI, bạn không cần phải thoát dấu ngoặc góc. Tất nhiên, dù sao đi nữa cũng không có hại gì, nhưng hãy nhìn vào sự nhầm lẫn mà bạn có thể tránh được. ;)
Alan Moore

Đôi khi tôi trốn thoát một cách không cần thiết khi tôi không chắc có thứ gì đó đặc biệt hay không. Tôi đã chỉnh sửa câu trả lời; nó hoạt động như nhau nhưng ngắn gọn hơn.
Lonnie hay nhất

Nhìn vào điều này bây giờ, tôi không biết tại sao tôi nghĩ bạn có ý đó \/, vì điều đó sẽ làm ngược lại các yêu cầu. Có thể tôi nghĩ rằng bạn đang cung cấp một mẫu bộ lọc tiêu cực.
Justin Morgan

54

Dường như với tôi, bạn đang cố gắng khớp các thẻ mà không có "/" ở cuối. Thử cái này:

<([a-zA-Z][a-zA-Z0-9]*)[^>]*(?<!/)>

8
Điều này không hoạt động. Đối với đầu vào '<xa = "<b>" /> <y>', các kết quả khớp là x và y, mặc dù x bị chấm dứt.
ceving

51

Đúng là khi lập trình, tốt nhất nên sử dụng các trình phân tích cú pháp và API chuyên dụng thay vì các biểu thức thông thường khi xử lý HTML, đặc biệt là nếu độ chính xác là tối quan trọng (ví dụ: nếu việc xử lý của bạn có thể có ý nghĩa bảo mật). Tuy nhiên, tôi không quy định cho một quan điểm giáo điều rằng việc đánh dấu kiểu XML không bao giờ được xử lý bằng các biểu thức thông thường. Có những trường hợp khi các biểu thức chính quy là một công cụ tuyệt vời cho công việc, chẳng hạn như khi thực hiện các chỉnh sửa một lần trong trình soạn thảo văn bản, sửa các tệp XML bị hỏng hoặc xử lý các định dạng tệp trông giống nhưng không hoàn toàn bằng XML. Có một số vấn đề cần lưu ý, nhưng chúng không thể vượt qua hoặc thậm chí không nhất thiết phải liên quan.

Một regex đơn giản như <([^>"']|"[^"]*"|'[^']*')*>thường là đủ tốt, trong những trường hợp như những gì tôi vừa đề cập. Đó là một giải pháp ngây thơ, tất cả mọi thứ được xem xét, nhưng nó cho phép chính xác >các ký hiệu không được mã hóa trong các giá trị thuộc tính. Nếu bạn đang tìm kiếm, ví dụ, một tablethẻ, bạn có thể điều chỉnh nó thành </?table\b([^>"']|"[^"]*"|'[^']*')*>.

Chỉ cần hiểu ý nghĩa của một biểu thức HTML "tiên tiến" hơn sẽ như thế nào, sau đây thực hiện một công việc khá đáng nể là mô phỏng hành vi trình duyệt trong thế giới thực và thuật toán phân tích cú pháp HTML5:

</?([A-Za-z][^\s>/]*)(?:=\s*(?:"[^"]*"|'[^']*'|[^\s>]+)|[^>])*(?:>|$)

Các điều sau đây khớp với định nghĩa khá nghiêm ngặt về các thẻ XML (mặc dù nó không tính đến toàn bộ các ký tự Unicode được phép trong các tên XML):

<(?:([_:A-Z][-.:\w]*)(?:\s+[_:A-Z][-.:\w]*\s*=\s*(?:"[^"]*"|'[^']*'))*\s*/?|/([_:A-Z][-.:\w]*)\s*)>

Cấp, những điều này không giải thích cho bối cảnh xung quanh và một vài trường hợp cạnh, nhưng ngay cả những điều như vậy cũng có thể được xử lý nếu bạn thực sự muốn (ví dụ: bằng cách tìm kiếm giữa các trận đấu của một regex khác).

Vào cuối ngày, sử dụng công cụ thích hợp nhất cho công việc, ngay cả trong trường hợp công cụ đó xảy ra là một biểu thức chính quy.


49

Mặc dù không phù hợp và hiệu quả khi sử dụng biểu thức chính quy cho mục đích đó, đôi khi các biểu thức chính quy cung cấp giải pháp nhanh chóng cho các vấn đề khớp đơn giản và theo quan điểm của tôi, việc sử dụng biểu thức chính quy cho các tác phẩm tầm thường không phải là điều đáng lo ngại.

Có một bài viết trên blog dứt khoát về việc kết hợp các yếu tố HTML trong cùng được viết bởi Steven Levithan.

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.