Використання регулярних виразів для розбору HTML: чому ні?


207

Схоже, що на кожне запитання про stackoverflow, коли запитувач використовує регулярний вираз для отримання інформації з HTML, неминуче буде відповідь, яка говорить про те, що не використовувати регулярний вираз для розбору HTML.

Чому ні? Я знаю, що існують цитати цитата "справжні" HTML-аналізатори, такі як Beautiful Soup , і я впевнений, що вони потужні і корисні, але якщо ви просто робите щось просте, швидке або брудне, то чому не заважайте використовувати щось настільки складне, коли кілька висловлювань регулярного вираження спрацюють нормально?

Більше того, чи є щось принципове, що я не розумію щодо регулярного вираження, що робить їх поганим вибором для розбору в цілому?


3
я думаю , що це боян з stackoverflow.com/questions/133601
jcrossley3

23
Тому що тільки Чак Норріс може розбір HTML з регулярним виразом (як пояснено в цій відомому Zalgo речі: stackoverflow.com/questions/1732348 / ... ).
приймає

1
Це питання змусило мене задати ще одне, яке якимось чином пов'язане. У випадку, якщо вас цікавить: Чому не можна використовувати регулярний гекс для розбору HTML / XML: офіційне пояснення в умовах непростої людини
mac


Це запитання було додано до поширених запитань щодо регулярного вираження стека в розділі "Загальні завдання на перевірку".
aliteralmind

Відповіді:


212

Весь синтаксичний розбір HTML неможливий із регулярними виразами, оскільки це залежить від відповідності відкриваючого та закриваючого тегів, що неможливо з регулярними виразами.

Регулярні вирази можуть відповідати лише звичайним мовам, але HTML - це контекстна мова, а не звичайна мова (Як зазначав @StefanPochmann, регулярні мови також є безконтекстними, тому контекстний не обов'язково означає не регулярний). Єдине, що ви можете зробити з регулярними виразами на HTML - це евристика, але це не буде працювати при будь-яких умовах. Повинно бути можливим представити HTML-файл, який буде неправильно зіставлений будь-яким регулярним виразом.


26
Найкраща відповідь поки що. Якщо він може відповідати лише звичайним граматикам, тоді нам знадобиться нескінченно великий регулярний вираз, щоб розібрати без контексту граматику, як HTML. Я люблю, коли ці речі мають чіткі теоретичні відповіді.
ntownsend

2
Я припускав, що ми обговорювали регекси типу Perl там, де вони насправді не є регулярними виразами.
Хенк Гей

5
Власне, .Net регулярні вирази можуть певною мірою відповідати відкриттю із закривальними тегами, використовуючи балансуючі групи та ретельно складений вираз. Зміщення всього цього в регулярному виразі все ще божевільне, звичайно, це виглядало б як великий код Chtulhu і, ймовірно, також викликає справжній. І врешті-решт це все ще не спрацює у всіх випадках. Вони кажуть, що якщо ви пишете регулярний вираз, який може правильно розібрати будь-який HTML, Всесвіт розпадеться на себе.
Алекс Павен

5
Деякі регекс-лібсини можуть робити рекурсивні регулярні вирази (ефективно роблячи їх нерегулярними виразами :)
Ondra Žižka

43
-1 Ця відповідь робить правильний висновок ("Неправильно розбирати HTML з Regex") з неправильних аргументів ("Тому що HTML не є звичайною мовою"). Те, що нині має на увазі більшість людей, коли вони говорять «регулярний вираз» (PCRE), здатний не тільки розбирати контекстні граматики (це фактично тривіально), але й контекстно-чутливі граматики (див. Stackoverflow.com/questions/7434272/ … ).
NikiC

35

Для швидкого двадцяти регулярного виразів буде добре. Але головне, що потрібно знати, це те, що неможливо побудувати регулярний вираз, який буде правильно аналізувати HTML.

Причина полягає в тому, що регулярні вирази не можуть обробляти довільно вкладені вирази. Див. Чи можуть використовуватися регулярні вирази для відповідності вкладеним шаблонам?


1
Деякі лінійки з регулярними виразами можуть робити рекурсивні регулярні вирази (ефективно роблячи їх нерегулярними виразами :)
Ondra Žižka

23

http://htmlparsing.com/regexes )

Скажіть, у вас є файл HTML, де ви намагаєтеся отримати URL-адреси з тегів <img>.

<img src="http://example.com/whatever.jpg">

Отже, ви пишете такий реджекс у Perl:

if ( $html =~ /<img src="(.+)"/ ) {
    $url = $1;
}

У цьому випадку $urlдійсно буде містити http://example.com/whatever.jpg. Але що відбувається, коли ви починаєте отримувати такий HTML:

<img src='http://example.com/whatever.jpg'>

або

<img src=http://example.com/whatever.jpg>

або

<img border=0 src="http://example.com/whatever.jpg">

або

<img
    src="http://example.com/whatever.jpg">

або ви починаєте отримувати помилкові позитиви від

<!-- // commented out
<img src="http://example.com/outdated.png">
-->

Це виглядає так просто, і він може бути простим для одного незмінного файлу, але для всього, що ви збираєтеся робити на довільних HTML-даних, регулярні вирази - це лише рецепт майбутнього душевного болю.


4
Це здається справжньою відповіддю - хоча, ймовірно, можливо проаналізувати довільний HTML за допомогою regex, оскільки сьогоднішні регулярні виразки є не просто обмеженими автоматизаторами, щоб проаналізувати довільний html, а не лише конкретну сторінку, вам доведеться повторно реалізувати HTML-аналізатор у regexp а регулярні виразки, безумовно, стають 1000 разів нечитабельними.
Smit Johnth

1
Гей Енді, я взяв час, щоб придумати вираз, який підтримує твої згадані випадки. stackoverflow.com/a/40095824/1204332 Дайте мені знати, що ви думаєте! :)
Іван Чаер

2
Аргументація в цій відповіді є способом застарілої і застосовується навіть менше сьогодні , ніж це було спочатку (який я думаю , що це не так). (Цитуючи OP: "якщо ви просто робите щось просте, швидке або брудне ...")
Sz.

16

Дві швидкі причини:

  • писати регулярний вираз, який може протистояти шкідливому введенню, важко; спосіб складніше, ніж використання заздалегідь вбудованого інструменту
  • писати регулярний вираз, який може працювати зі смішною розміткою, до якої неминуче застряєш, важко; спосіб складніше, ніж використання заздалегідь вбудованого інструменту

Що стосується придатності регулярних виразів для розбору в цілому: вони не підходять. Ви коли-небудь бачили види реджексів, які вам знадобляться для розбору більшості мов?


2
Ого? Зниження через 2+ років? У випадку, якщо хтось цікавився, я не сказав "Тому що це теоретично неможливо", тому що чітко задавали питання про "швидко і брудно", а не "правильно". ОП чітко вже прочитала відповіді, які охоплювали теоретично неможливу територію і досі не були задоволені.
Хенк Гей

1
Отримайте нагороду після 5+ років. :) Щодо того, чому ви, можливо, отримали голосування, я не кваліфікований, але особисто я хотів би побачити кілька прикладів чи пояснень, а не заключне риторичне питання.
Адам Дженсен

3
По суті, весь швидкий і брудний аналіз HTML, який виконується в транспортних продуктах або внутрішніх інструментах, закінчується тим, що прорізається безпека, або помилка, яка чекає цього. Це повинно бути відверто від пориву. Якщо можна використовувати регулярний вираз, можна скористатися належним html-аналізатором.
Відновіть Моніку

16

Що стосується розбору, регулярні вирази можуть бути корисними на етапі "лексичного аналізу" (лексеру), де вхід розбивається на лексеми. Це менш корисно на фактичному етапі "побудувати розбір дерева".

Щодо HTML-аналізатора, я б очікував, що він приймає лише добре сформований HTML, і для цього потрібні можливості за межами того, що може робити звичайний вираз (вони не можуть "порахувати" та переконайтеся, що задана кількість елементів, що відкриваються, врівноважується тим самим числом замикаючих елементів).


8

Оскільки існує багато способів "накрутити" HTML, який браузери будуть обробляти досить ліберально, але знадобиться чимало зусиль, щоб відтворити ліберальну поведінку браузера, щоб покрити всі випадки регулярними виразами, тому ваш регулярний вираз неминуче вийде з ладу на якомусь спеціальному випадків, і це, можливо, призведе до серйозних прогалин у вашій системі.


1
Дуже правда, більшість HTML там здається жахливим. Я не розумію, як невдалий регулярний вираз може ввести серйозні прогалини в безпеці. Чи можете ви навести приклад?
ntownsend

4
ntownsend: Наприклад, ви думаєте, що ви позбавили всіх тегів сценарію з HTML, але ваш регулярний вираз не охоплює особливий випадок (який, скажімо, працює лише на IE6): бум, у вас є вульєзність XSS!
Тамас Цінеге

1
Це був строго гіпотетичний приклад, оскільки більшість прикладів реального світу занадто складні, щоб вписатись у ці коментарі, але їх можна було швидко знайти, побіжно погукавшись.
Тамас Цінеге

3
+1 для згадування кута захисту. Коли ви взаємодієте з усім Інтернетом, ви не можете дозволити собі писати хакі "код працює більшу частину часу".
j_random_hacker

7

Проблема полягає в тому, що більшість користувачів, які задають питання, пов’язане з HTML та regex, роблять це, оскільки вони не можуть знайти власний регулярний вираз. Тоді варто подумати, чи все було б простіше при використанні аналізатора DOM або SAX чи чогось подібного. Вони оптимізовані та побудовані для роботи з XML-подібними структурами документів.

Звичайно, є проблеми, які можна легко вирішити регулярними виразами. Але акцент робиться на легко .

Якщо ви просто хочете знайти всі URL-адреси, які виглядають так, як у http://.../вас добре, з regexps. Але якщо ви хочете знайти всі URL-адреси, що знаходяться в a-Element, який має клас "mylink", ви, ймовірно, краще скористатися відповідним аналізатором.


6

Регулярні вирази не були розроблені для обробки вкладеної структури тегів, і в кращому випадку складно (в гіршому випадку неможливо) обробляти всі можливі крайові випадки, які ви отримуєте з реальним HTML.


6

Я вважаю, що відповідь полягає в теорії обчислень. Для розбору мови за допомогою регулярного вираження він повинен бути за визначенням "регулярний" ( посилання ). HTML не є звичайною мовою, оскільки не відповідає ряду критеріїв для звичайної мови (багато що стосується багатьох рівнів вкладеності, притаманних коду html). Якщо вас цікавить теорія обчислень, я рекомендував би цю книгу.


1
Я фактично прочитав цю книгу. Мені просто не спало на думку, що HTML - це без контексту мова.
ntownsend

4

Цей вираз отримує атрибути з елементів HTML. Він підтримує:

  • атрибути без котирування / котирування,
  • одинарні / подвійні котирування,
  • уникнулі цитати всередині атрибутів,
  • пробіли навколо рівних знаків,
  • будь-яка кількість атрибутів,
  • перевіряти лише атрибути всередині тегів,
  • втечі коментарів та
  • керуйте різними лапками у значенні атрибута.

(?:\<\!\-\-(?:(?!\-\-\>)\r\n?|\n|.)*?-\-\>)|(?:<(\S+)\s+(?=.*>)|(?<=[=\s])\G)(?:((?:(?!\s|=).)*)\s*?=\s*?[\"']?((?:(?<=\")(?:(?<=\\)\"|[^\"])*|(?<=')(?:(?<=\\)'|[^'])*)|(?:(?!\"|')(?:(?!\/>|>|\s).)+))[\"']?\s*)

Перевірте це . Він краще працює з прапорами "gisx", як у демонстраційній версії.


1
Це дуже цікаво. Не читабельний, напевно важко налагодити, але все-таки: Вражаюча робота!
Ерік Думініл

Це все ще невиразно передбачає, що HTML добре сформований. Без відповідності контексту, це відповідатиме видимим URL-адресам у контекстах, де ти зазвичай не хочеш їх відповідати, як у фрагменті коду JavaScript всередині <script>тегу.
трійчатка

4

HTML / XML поділяється на розмітку та вміст. Regex корисний лише для розбору лексичного розбору тегів. Я думаю, ви могли б вивести вміст. Це був би хороший вибір для аналізатора SAX. Теги та контент можуть бути доставлені на визначену користувачем функцію, де можна відстежувати введення / закриття елементів.

Що стосується просто розбору тегів, це можна зробити за допомогою регулярного вираження та використовувати для викреслення тегів з документа.

За роки тестування я виявив секрет того, як браузери аналізують теги, як добре, так і погано сформовані.

Нормальні елементи розбираються з цією формою:

Ядро цих тегів використовує цей регулярний вираз

 (?:
      " [\S\s]*? " 
   |  ' [\S\s]*? ' 
   |  [^>]? 
 )+

Ви помітите це [^>]?як одне з чергувань. Це буде відповідати незбалансованим цитатам з неправильно сформованих тегів.

Це також є єдиним коренем всього зла до регулярних виразів. Те, як воно використовується, викликає перешкоду, щоб задовольнити його жадібний, повинен відповідати кількісно визначеному контейнеру.

Якщо використовується пасивно, жодних проблем не виникає. Але якщо ви змусите щось збігатися, перетлумачивши його потрібним парним атрибутом / значенням і не забезпечивши належного захисту від зворотного відстеження, це кошмар поза контролем.

Це загальна форма лише для простих старих тегів. Помічаєте [\w:]представницьку назву тегу? Насправді легальні символи, що представляють назву тегів, - це неймовірний список символів Unicode.

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

Вперед, ми також бачимо, що ви просто не можете шукати конкретний тег без аналізу ВСІХ тегів. Я маю на увазі, що ви могли б, але для цього доведеться використовувати комбінацію дієслів типу (* SKIP) (* FAIL), але все-таки всі теги мають бути розібрані.

Причина полягає в тому, що синтаксис тегів може бути прихований всередині інших тегів тощо.

Отже, для пасивного розбору всіх тегів потрібен регулярний вираз, як наведений нижче. Цей конкретний також відповідає невидимому вмісту .

Оскільки новий HTML або xml або будь-який інший розробляють нові конструкції, просто додайте їх як одне з чергувань.


Примітка веб-сторінки - я ніколи не бачив веб-сторінки (або xhtml / xml), з якою із цим
виникли проблеми. Якщо ви знайдете його, дайте мені знати.

Примітка про ефективність - Це швидко. Це найшвидший аналізатор тегів, який я бачив
(може бути, швидше, хто знає).
У мене є кілька конкретних версій. Він також чудовий як скрепер
(якщо ви практичний тип).


Повна сировина

<(?:(?:(?:(script|style|object|embed|applet|noframes|noscript|noembed)(?:\s+(?>"[\S\s]*?"|'[\S\s]*?'|(?:(?!/>)[^>])?)+)?\s*>)[\S\s]*?</\1\s*(?=>))|(?:/?[\w:]+\s*/?)|(?:[\w:]+\s+(?:"[\S\s]*?"|'[\S\s]*?'|[^>]?)+\s*/?)|\?[\S\s]*?\?|(?:!(?:(?:DOCTYPE[\S\s]*?)|(?:\[CDATA\[[\S\s]*?\]\])|(?:--[\S\s]*?--)|(?:ATTLIST[\S\s]*?)|(?:ENTITY[\S\s]*?)|(?:ELEMENT[\S\s]*?))))>

Форматований вигляд

 <
 (?:
      (?:
           (?:
                # Invisible content; end tag req'd
                (                             # (1 start)
                     script
                  |  style
                  |  object
                  |  embed
                  |  applet
                  |  noframes
                  |  noscript
                  |  noembed 
                )                             # (1 end)
                (?:
                     \s+ 
                     (?>
                          " [\S\s]*? "
                       |  ' [\S\s]*? '
                       |  (?:
                               (?! /> )
                               [^>] 
                          )?
                     )+
                )?
                \s* >
           )

           [\S\s]*? </ \1 \s* 
           (?= > )
      )

   |  (?: /? [\w:]+ \s* /? )
   |  (?:
           [\w:]+ 
           \s+ 
           (?:
                " [\S\s]*? " 
             |  ' [\S\s]*? ' 
             |  [^>]? 
           )+
           \s* /?
      )
   |  \? [\S\s]*? \?
   |  (?:
           !
           (?:
                (?: DOCTYPE [\S\s]*? )
             |  (?: \[CDATA\[ [\S\s]*? \]\] )
             |  (?: -- [\S\s]*? -- )
             |  (?: ATTLIST [\S\s]*? )
             |  (?: ENTITY [\S\s]*? )
             |  (?: ELEMENT [\S\s]*? )
           )
      )
 )
 >

3

Хоча "це залежить". Це правда, що регулярні вирази не можуть і не можуть аналізувати HTML з справжньою точністю з усіх причин, наведених тут. Якщо, однак, наслідки помилки (наприклад, не обробка вкладених тегів) є незначними, і якщо регулярні вирази супер зручні у вашому оточенні (наприклад, коли ви зламаєте Perl), продовжуйте працювати.

Припустимо, ти, о, можливо, розбираєш веб-сторінки, які посилаються на твій сайт - можливо, ти знайшов їх за допомогою пошуку посилань Google - і ти хочеш швидкий спосіб отримати загальне уявлення про контекст оточення вашого посилання. Ви намагаєтеся скласти невеликий звіт, який може попередити вас пов’язати спам.

У цьому випадку помилкове оформлення деяких документів не буде великою справою. Ніхто, окрім вас, не побачить помилок, і якщо вам пощастить, їх буде замало, що ви зможете прослідкувати індивідуально.

Я думаю, я кажу, що це компроміс. Іноді реалізація або використання правильного аналізатора - настільки простий, як це може бути - може не мати труднощів, якщо точність не є критичною.

Просто будьте обережні зі своїми припущеннями. Я можу придумати декілька способів, як ярлик для regexp може дати відмінність, якщо ви намагаєтеся розібрати щось, що буде показано, наприклад, у відкритому доступі.


3

Однозначно є випадки, коли використання регулярного виразу для розбору деякої інформації з HTML є правильним шляхом - це багато що залежить від конкретної ситуації.

Вищенаведена думка полягає в тому, що загалом це погана ідея. Однак якщо структура HTML відома (і навряд чи зміниться), це все-таки дійсний підхід.


3

Майте на увазі, що хоча сам HTML не є регулярним, частини сторінки, яку ви переглядаєте, можуть бути регулярними.

Наприклад, це помилка <form>вкладених тегів; якщо веб-сторінка працює коректно, то використовувати регулярний вираз, щоб схопити a, <form>було б цілком розумним.

Нещодавно я робив кілька веб-скребків, використовуючи лише селен та регулярні вирази. Я пішов з ним , тому що дані , які я хотів було покласти в <form>, і поставити в простому форматі таблиці (так що я міг розраховувати навіть на <table>, <tr>і <td>бути невложенних - що насправді дуже незвично). У якійсь мірі регулярні вислови були навіть майже необхідними, тому що частина структури, до якої я потребував доступу, була обмежена коментарями. (Красивий суп може давати вам коментарі, але це було б важко схопити <!-- BEGIN -->і <!-- END -->заблокувати за допомогою Beautiful Soup.)

Якби я мав турбуватися про вкладені таблиці, однак мій підхід просто не працював би! Мені довелося б відкинутись на Beautiful Soup. Однак навіть іноді ви можете використовувати звичайний вираз, щоб схопити потрібний шматок, а потім прокрутити звідти.


2

Насправді, HTML-аналіз з регексом цілком можливий у PHP. Вам просто потрібно проаналізувати весь рядок назад, використовуючи strrposдля пошуку <та повторення звідти регулярного виразу, використовуючи специфікатори ungreedy щоразу, щоб переходити над вкладеними тегами. Не дуже фантастично та дуже повільно на великих речах, але я використовував це для власного особистого редактора шаблонів для свого веб-сайту. Я насправді не розбирав HTML, але кілька спеціальних тегів, які я зробив для запитів записів у базі даних для відображення таблиць даних (мій <#if()>тег міг таким чином виділити спеціальні записи). Я не був готовий піти на аналізатор XML лише на кілька створених власноруч тегів (із дуже не XML-даними в них) тут і там.

Тож, хоча це питання значно мертве, воно все одно з’являється в пошуку Google. Я прочитав його і подумав, що "виклик прийнятий" і закінчив виправляти мій простий код без необхідності замінювати все. Вирішив запропонувати іншу думку кожному, хто шукає подібну причину. Також остання відповідь була опублікована 4 години тому, тому це все ще гаряча тема.


2
-1 за те, що запропонував ГОТОВУ ідею. Чи розглядали ви пробіл між тегом та кутом закриття? (Наприклад, <tag >) Чи розглядали ви коментовані закривальні теги? (Наприклад, <tag> <!-- </tag> -->) Чи вважали ви CDATA? Чи розглядали ви непомітні теги регістру? (Наприклад, <Tag> </tAG>) Ви також це враховували ?
rmunn

1
У конкретному випадку ваших декількох спеціальних тегів, так, регулярні вирази працюють добре. Тож не те, що ваше використання їх було помилкою у вашому конкретному випадку . Але це не HTML, і сказати, що "PH синтаксичний аналіз за допомогою регулярного вираження цілком можливий в PHP" - це просто неправдива помилка та ГОЛОВНА ідея. Невідповідності справжнього HTML (а їх набагато більше, ніж декілька перерахованих я), чому ви ніколи не повинні розбирати реальний HTML за допомогою регулярних виразів. Дивіться, добре, всі інші відповіді на це питання, а також той, на який я посилався в своєму іншому коментарі вище.
rmunn

2
PHP є повноцінною мовою, тому це зовсім неправдиво. Можливе все обчислення, включаючи аналіз HTML. Пробіли в тегах НІКОЛИ не були проблемою, і я з тих пір адаптував її до переліку елементів тегів у порядку. Моє використання автоматично виправляло теги з непослідовним кожухом, позбавленим коментованих матеріалів на самому першому етапі, а після деяких пізніших доповнень усілякі теги можуть бути легко додані (хоча на власний вибір це чутливі до регістру). І я впевнений, що CDATA насправді є XML-елементом, а не HTML-елементом.
Deji

2
Мій старий метод (який я описав тут) був досить неефективним, і я нещодавно почав переписувати багато редакторів контенту. Що стосується таких дій, можливість не є проблемою; найкращий спосіб - це завжди головна турбота. Справжня відповідь - "у PHP немає ЛЕГОГО способу зробити це". Ніхто не каже, що немає можливості зробити це в PHP або що це жахлива ідея, але що це неможливо з регулярним виразом, якого я, чесно кажучи, ніколи не пробував, але головним недоліком у моїй відповіді є припущення, що питання стосувалося регексу в контексті PHP, що не обов'язково.
Deji

2

Я також спробував свої сили на регулярному вираженні для цього. Це в основному корисно для пошуку фрагментів вмісту, сполучених із наступним тегом HTML, і він не шукає відповідних близьких тегів, але він підбере тісні теги. Прокрутіть стек своєю мовою, щоб перевірити їх.

Використовуйте з параметрами 'sx'. "також", якщо вам пощастило:

(?P<content>.*?)                # Content up to next tag
(?P<markup>                     # Entire tag
  <!\[CDATA\[(?P<cdata>.+?)]]>| # <![CDATA[ ... ]]>
  <!--(?P<comment>.+?)-->|      # <!-- Comment -->
  </\s*(?P<close_tag>\w+)\s*>|  # </tag>
  <(?P<tag>\w+)                 # <tag ...
    (?P<attributes>
      (?P<attribute>\s+
# <snip>: Use this part to get the attributes out of 'attributes' group.
        (?P<attribute_name>\w+)
        (?:\s*=\s*
          (?P<attribute_value>
            [\w:/.\-]+|         # Unquoted
            (?=(?P<_v>          # Quoted
              (?P<_q>['\"]).*?(?<!\\)(?P=_q)))
            (?P=_v)
          ))?
# </snip>
      )*
    )\s*
  (?P<is_self_closing>/?)   # Self-closing indicator
  >)                        # End of tag

Цей розроблений для Python (він може працювати для інших мов, його не пробували, він використовує позитивні динаміки пошуку, негативні погляди і названі зворотні посилання). Підтримує:

  • Відкрити тег - <div ...>
  • Закрити тег - </div>
  • Коментар - <!-- ... -->
  • CDATA - <![CDATA[ ... ]]>
  • Тег, що самозакривається - <div .../>
  • Необов’язкові значення атрибутів - <input checked>
  • Значення атрибутів без котирування / котирування - <div style='...'>
  • Одиночні / подвійні котирування - <div style="...">
  • Цитати, що уникнули - <a title='John\'s Story'>
    (це не дійсно HTML, але я хороший хлопець)
  • Проміжки навколо рівних знаків - <a href = '...'>
  • Названі знімки для цікавих біт

Це також непогано про те, щоб не спрацьовувати на неправильно сформованих тегах, як, наприклад, коли ви забудете a <або >.

Якщо ваш аромат regex підтримує неодноразові зйомки з ім'ям, то ви золоті, але Python reне знає (я знаю, що регекс це робить, але мені потрібно використовувати ванільний Python). Ось що ви отримуєте:

  • content- Весь вміст до наступного тегу. Ви можете це залишити.
  • markup - Весь тег із усім, що в ньому.
  • comment - Якщо це коментар, зміст коментаря.
  • cdata- Якщо це а <![CDATA[...]]>, вміст CDATA.
  • close_tag- Якщо це тісний тег ( </div>), назва тегу.
  • tag- Якщо це відкритий тег ( <div>), назва тегу.
  • attributes- Усі атрибути всередині тегу. Використовуйте це, щоб отримати всі атрибути, якщо у вас немає повторних груп.
  • attribute - Повторне, кожен атрибут.
  • attribute_name - Повторне, кожне ім’я атрибута.
  • attribute_value- Повторне значення кожного значення. Сюди входять цитати, якщо вони були котировані.
  • is_self_closing- Це /якщо це тег, що самозакривається, інакше нічого.
  • _qі _v- ігноруйте ці; вони використовуються внутрішньо для зворотних посилань.

Якщо ваш регекс-движок не підтримує повторні імена захоплення, є розділ, який називається, який ви можете використовувати для отримання кожного атрибута. Просто запустіть цей регулярний вираз на attributesгрупі, щоб отримати кожен attribute, attribute_nameі attribute_valueвийти з нього.

Демонстрація тут: https://regex101.com/r/mH8jSu/11


1

Регулярні вирази недостатньо потужні для такої мови, як HTML. Звичайно, є кілька прикладів, коли можна використовувати регулярні вирази. Але загалом це не підходить для розбору.


0

Ви знаєте ... тут багато менталітету ви НЕ МОЖЕТЕ це зробити, і я думаю, що всі з обох боків огорожі - це правильно і неправильно. Ви МОЖЕТЕ це зробити, але для цього потрібно трохи більше, ніж просто запустити один регулярний вираз. Візьміть це (я писав це протягом години) як приклад. Він передбачає, що HTML є повністю дійсним, але залежно від того, якою мовою ви користуєтесь, щоб застосувати вищезгаданий регулярний вираз, ви можете зафіксувати HTML, щоб переконатися, що він буде успішним. Наприклад, видалення закриваючих тегів, яких не повинно бути там: </img>наприклад. Потім додайте єдиний косою переднім кодом HTML до елементів, які їх відсутні, тощо.

Я б використовував це в контексті написання бібліотеки, яка б дозволила мені виконувати пошук елементів HTML, подібних до того, наприклад, у JavaScript [x].getElementsByTagName(). Я б просто з’єднав функціонал, який я написав у розділі DEFINE в регулярному виразі, і використати його для введення всередину дерева елементів, по одному.

Отже, це буде остаточним 100% відповіддю для перевірки HTML? Ні. Але це початок, і трохи більше роботи можна зробити. Однак намагатися зробити це в одному виконанні регулярних виразів не є практичним і неефективним.

Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.