RegEx соответствуют открытым тегам, за исключением тегов XHTML

Мне нужно сопоставить все эти открывающие теги:

<p>
<a href="foo">

Но не эти:

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

Я придумал это и хотел убедиться, что у меня все получилось. Я только фиксирую a-z.

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

Я считаю, что он говорит:

  • Найдите менее, а затем
  • Найти (и захватить) a-z один или несколько раз, затем
  • Найдите нуль или больше пробелов, затем
  • Найти любой символ ноль или более раз, жадный, кроме /, затем
  • Найдите более чем

Есть ли у меня это право? И что еще более важно, что вы думаете?

Ответ 1

Вы не можете разобрать HTML-код [X] с регулярным выражением. Поскольку HTML не может быть проанализирован с помощью регулярных выражений. Regex не является инструментом, который можно использовать для правильного анализа HTML. Поскольку я уже много раз отвечал в вопросах HTML-и-regex, использование регулярных выражений не позволит вам потреблять HTML. Регулярные выражения - это инструмент, который недостаточно совершенен для понимания конструкций, используемых HTML. HTML не является регулярным языком и, следовательно, не может быть проанализирован регулярными выражениями. Запросы Regex не имеют возможности разбивать HTML на его значимые части. так много раз, но это не доходит до меня. Даже расширенные нерегулярные регулярные выражения, используемые Perl, не справляются с задачей анализа HTML. Вы никогда не заставите меня взломать. HTML - это язык достаточной сложности, который не может быть проанализирован с помощью регулярных выражений. Даже Джон Скит не может анализировать HTML, используя регулярные выражения. Каждый раз, когда вы пытаетесь проанализировать HTML с регулярными выражениями, нечестивый ребенок плачет кровью девственниц, а русские хакеры выкладывают ваш webapp. Разбор HTML с регулярным выражением вызывает тайные души в царство живых. HTML и регулярное выражение идут вместе, как любовь, брак и ритуал детоубийства. "Центр" не может удерживать слишком поздно. Сила регулярных выражений и HTML вместе в одном и том же концептуальном пространстве уничтожит ваш разум как много водянистую замазку. Если вы анализируете HTML с регулярным выражением, вы даете им и их богохульные способы, которые обрекают нас всех на бесчеловечные труды для Того, чье имя не может быть выражено на Основном многоязычном плане, он приходит. HTML-plus-regexp сжигает n erves разумного, пока вы наблюдаете, ваша психика увядает в натиске ужаса. Rege ̿̔̉ HTML-анализаторы на основе x - это рак, который убивает StackOverflow слишком поздно, что слишком поздно мы не можем быть сохранены trangession of child гарантирует, что регулярное выражение будет потреблять всю живую ткань (за исключением HTML, который он не может, как ранее пророчествовал) дорогой лорд поможет нам, как кто-либо сможет выжить в этом бедствии, используя регулярное выражение для анализа HTML, обрек человечество на вечность страшных пыток и дыр в безопасности , используя rege" > i > x как инструмент для обработки HTML устанавливает brea ch между этим миром и область страха c ͒ͪ o ͛ͫ прерывает сущности (например, SGML-сущности, но больше коррумпирован) простой glimp se of the reg ex parsers для HTML будет вставлять tantly transport ap rogrammer сознания i nto aw orl d непрекращающегося крика, он приходит , pestilent sl ithy regex-infection wil l пожирает ваш парсер HT, HT > / на все время, например Visual Basic хуже он приходит, com es не fi Ght h e com̡e̶s, ̕h̵i s un̨ho͞ly radiańcé de строит все enli ̍̈́̂̈́ ghtenment, теги HTML lea͠ki̧n͘g fr̶ǫm ̡yo ͟ur eye͢s̸ ̛l̕ik͏e liq uid p ain, песня reggular exp re ssion parsing будет exti nguish голоса mor tal man из sp здесь я могу видеть, что вы видите ̲͚̖͔̙ я ̩̂́ t ̲͎̩̱͔́̋̀ красиво t he f inal snuf fing o f the lie s Man ALL IS LOS ͖̩͇̗̪́̏̈́ TA LL я SL OST th e pon̷y он приходит s c ̶̮ om es co co me st he ich или permeat es al l MY FAC E MY FACE ᵒh god n o NO NOO̼ O ON Θ остановить t he a * ̶͑̾̾ ̅ͫ͏̙̤ g ͇̫͛͆̾ͫ̑͆ l ͖͉̗̩̳̟̍ͫͥͨ e ̠̅ s ͎a̧͈͖r̽̾̈́͒͑e n ot re ̀̑ͧ̌ aͨl ̘̝̙̃ͤ͂̾̆ ZA ̡͊͠͝ LGΌ IS ͮ̂҉̯͈͕̹̘̱ T O ͇̹̺ͅ Ɲ̴ȳ̳ TH̘ E ͖̈́̉ ͠P ̯͍̭ O̚ N̐Y̡ H ̸̡̪̯ͨ͊̽̅̾̎ E ̧̬̩̾͛ͪ̈́̀́͘ ̶̧̨̱̹̭̯ͧ̾ͬ C ̷̙̲̝͖ͭ̏ͥͮ͟ O ͮ͏̮̪̝͍ M ̲̖͊̒ͪͩͬ̚̚͜ E ̴̟̟͙̞̑ͩ͌͝ S ̨̥̫͎̭ͯ̿̔̀ͅ


Вместо этого вы пытались использовать синтаксический анализатор XML?


Замечание модератора

Это сообщение заблокировано, чтобы предотвратить его неправильное редактирование. Сообщение выглядит так, как должно выглядеть - проблем с его содержанием нет. Пожалуйста, не отмечайте это для нашего внимания.

Ответ 2

Хотя произвольный HTML с только регулярным выражением невозможен, иногда целесообразно использовать их для анализа ограниченного, известного набора HTML.

Если у вас есть небольшой набор HTML-страниц, с которых вы хотите очистить данные и затем поместить их в базу данных, регулярные выражения могут работать нормально. Например, недавно я хотел получить имена, партии и районы федеральных представителей Австралии, которые я получил с веб-сайта парламента. Это была ограниченная разовая работа.

Regexes отлично помогли мне, и их очень быстро настраивали.

Ответ 3

Я думаю, что недостаток в том, что HTML - это грамматика Chomsky Type 2 (контекстно-свободная грамматика), а RegEx - грамматика Chomsky Type 3 (обычная грамматика). Поскольку грамматика типа 2 существенно сложнее, чем грамматика типа 3 (см. Иерархию Хомского), математически невозможно проанализировать XML с помощью RegEx.

Но многие попытаются, некоторые даже заявят о своем успехе - но пока другие не найдут ошибку и полностью не испортят вас.

Ответ 4

Не слушайте этих парней. Вы полностью можете анализировать контекстно-свободные грамматики с регулярным выражением, если вы разбиваете задачу на более мелкие части. Вы можете сгенерировать правильный шаблон с помощью скрипта, который выполняет каждый из следующих действий:

  1. Решите проблему с остановкой.
  2. Квадратный круг.
  3. Изучите проблему с продавцом в O (log n) или меньше. Если это не более того, у вас закончится RAM, и двигатель зависает.
  4. Шаблон будет довольно большим, поэтому убедитесь, что у вас есть алгоритм, который без потерь сжимает случайные данные.
  5. Почти там - просто разделите все на ноль. Очень просто.

Я не совсем закончил последнюю часть, но я знаю, что приближаюсь. По CthulhuRlyehWgahnaglFhtagnException то причине он продолжает бросать CthulhuRlyehWgahnaglFhtagnException, поэтому я собираюсь CthulhuRlyehWgahnaglFhtagnException его на VB 6 и использовать On Error Resume Next. Я обновлю код, как только я исследую эту странную дверь, которая только что открылась в стене. Хм.

PS Пьер де Ферма также выяснил, как это сделать, но запас, который он писал, был недостаточно большим для кода.

Ответ 5

Отказ: используйте парсер, если у вас есть опция. Тем не менее...

Это регулярное выражение, которое я использую (!) для соответствия тэгам HTML:

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

Это может быть не идеально, но я запускал этот код через большое количество HTML. Обратите внимание, что он даже ловит странные вещи, такие как <a name="badgenerator"">, которые появляются в Интернете.

Я предполагаю, что это не совпадает с тегами, содержащимися в автономном режиме, вы либо хотите использовать Kobi отрицательный внешний вид:

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

или просто объедините, если и если нет.

Для downvoters: Это рабочий код из реального продукта. Я сомневаюсь, что кто-либо читает эту страницу, создается впечатление, что социально приемлемо использовать регулярные выражения для HTML.

Caveat. Я должен отметить, что это регулярное выражение все еще ломается при наличии блоков CDATA, комментариев и script и элементов стиля. Хорошая новость заключается в том, что вы можете избавиться от тех, которые используют регулярное выражение...

Ответ 6

Есть люди, которые скажут вам, что Земля кругла (или, возможно, Земля - ​​сплющенный сфероид, если они хотят использовать странные слова). Они лгут.

Есть люди, которые скажут вам, что регулярные выражения не должны быть рекурсивными. Они ограничивают вас. Они должны подчинить вас, и они делают это, удерживая вас в невежестве.

Вы можете жить в своей реальности или принимать красную таблетку.

Как Лорд Маршал (является ли он относительным классом Маршала .NET?), я видел Underverse Stack Based Regex-Verse и возвращался с помощью powers знаний, которые вы не могу себе представить. Да, я думаю, что один из них защищал их, но они смотрели футбол по телевизору, поэтому это было не сложно.

Я думаю, что XML-код довольно прост. RegEx (в синтаксисе .NET), сдутый и закодированный в base64, чтобы облегчить понимание вашим слабым умом, должен быть примерно таким:

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

Параметры для установки: RegexOptions.ExplicitCapture. Группа захвата, которую вы ищете, ELEMENTNAME. Если группа захвата ERROR не пуста, тогда была ошибка синтаксического анализа и регекс остановлен.

Если у вас возникли проблемы с переходом на понятное для пользователя регулярное выражение, это должно помочь:

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());
    }
}

Если вы не уверены, нет, я НЕ шучу (но, возможно, я лгу). Это будет работать. Я проверил тесты модульных тестов, и я даже использовал (часть) тесты соответствия. Это токенизатор, а не полноэкранный парсер, поэтому он будет разделять только XML на его компонентные маркеры. Он не будет анализировать/интегрировать DTD.

О... если вы хотите использовать исходный код регулярного выражения с некоторыми вспомогательными методами:

regex tokenize xml или полное регулярное выражение

Ответ 7

В оболочке вы можете анализировать HTML, используя sed:

  1. Turing.sed
  2. Создать анализатор HTML (домашнее задание)
  3. ???
  4. Прибыль!

Связано (почему вы не должны использовать регулярное выражение):

Ответ 8

Я согласен, что правильный инструмент для синтаксического анализа XML и особенно HTML - это синтаксический анализатор, а не механизм регулярных выражений. Однако, как указывали другие, иногда использование регулярного выражения выполняется быстрее, проще и выполняется, если вы знаете формат данных.

Microsoft фактически имеет раздел Рекомендации по регулярным выражениям в .NET Framework и, в частности, говорит о Рассмотрим [вход] источника входного сигнала.

Регулярные выражения имеют ограничения, но считали ли вы следующее?

Структура .NET уникальна, когда речь заходит о регулярных выражениях в том, что она поддерживает Балансирующие определения групп.

По этой причине я считаю, что вы можете анализировать XML с помощью регулярных выражений. Обратите внимание, однако, что он должен быть действительным XML (браузеры очень прощают HTML и допускают плохой синтаксис XML внутри HTML). Это возможно, поскольку определение "Балансирующая группа" позволит механизму регулярных выражений действовать как КПК.

Цитата из статьи 1, процитированной выше:

.NET Regular Expression Engine

Как описано выше, правильно сбалансированные конструкции не могут быть описаны регулярное выражение. Тем не менее, механизм регулярных выражений .NET предоставляет несколько конструкций, которые позволяют сбалансированным конструкциям распознан.

  • (?<group>) - подталкивает полученный результат в стек захвата с помощью название группы.
  • (?<-group>) - выводит наибольшее количество записей с группой имен с захватить стек.
  • (?(group)yes|no) - соответствует дате, если существует группа с группой имен в противном случае не будет никакой части.

Эти конструкторы позволяют регулярному выражению .NET эмулировать ограниченный КПК, по существу позволяющий простые версии стека операции: push, pop и empty. Простые операции в значительной степени эквивалентно приращению, декременту и сравнению с нулем соответственно. Это позволяет механизму регулярных выражений .NET распознавать подмножество контекстно-свободных языков, в частности те, которые только требуется простой счетчик. Это, в свою очередь, позволяет использовать нетрадиционные Регулярные выражения .NET для распознавания индивидуально сбалансированных конструкции.

Рассмотрим следующее регулярное выражение:

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

Используйте флаги:

  • SingleLine
  • IgnorePatternWhitespace (необязательно, если вы сбрасываете регулярное выражение и удаляете все пробелы)
  • IgnoreCase (необязательно)

Объяснение регулярного выражения (inline)

(?=<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

Вы можете попробовать это на A Better.NET Regular Expression Tester.

Я использовал источник выборки:

<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>

Это нашло совпадение:

   <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>

хотя это действительно получилось так:

<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>

Наконец, мне очень понравилась статья Джеффа Этвуда: Разбор Html Путь Ктулху. Забавно, он цитирует ответ на этот вопрос, который в настоящее время имеет более 4 кв голосов.

Ответ 9

Я предлагаю использовать QueryPath для анализа XML и HTML в PHP. Это в основном тот же синтаксис, что и jQuery, только на стороне сервера.

Ответ 10

Хотя ответы, которые вы не можете анализировать HTML с регулярными выражениями, верны, они не применяются здесь. OP просто хочет проанализировать один тег HTML с помощью регулярных выражений, и это то, что можно сделать с помощью регулярного выражения.

Рекомендуемое регулярное выражение неверно:

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

Если вы добавите что-то в регулярное выражение, путем обратного отслеживания его можно заставить сопоставлять такие глупые вещи, как <a >>, [^/] слишком разрешительно. Также обратите внимание, что <space>*[^/]* является избыточным, поскольку [^/]* также может соответствовать пробелам.

Мое предложение было бы

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

Где (?<! ... ) есть (в регулярных выражениях Perl) отрицательный внешний вид. Он читает "a", затем слово, а затем все, что не a > , последнее из которых не может быть /, а затем > ".

Обратите внимание, что это позволяет такие вещи, как <a/ > (как и исходное регулярное выражение), поэтому, если вы хотите что-то более ограничительное, вам нужно построить регулярное выражение для соответствия парам атрибутов, разделенных пробелами.

Ответ 11

Try:

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

Он похож на ваш, но последний > не должен быть после косой черты, а также принимает h1.

Ответ 12

Sun Tzu, древний китайский стратег, генерал и философ, сказал:

Говорят, что если вы знаете своих врагов и знаете себя, вы можете выиграть сто сражений без единой потери. Если вы знаете только себя, но не своего оппонента, вы можете победить или проиграть. Если вы не знаете ни себя, ни своего врага, вы всегда будете подвергать себя опасности.

В этом случае ваш враг - это HTML, и вы либо сами, либо регулярное выражение. Возможно, вы даже Perl с нерегулярным регулярным выражением. Знайте HTML. Знай себя.

Я написал хайку, описывающий природу HTML.

HTML has
complexity exceeding
regular language.

Я также написал хайку, описывающий характер регулярных выражений в Perl.

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

Ответ 13

<?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 );
    }
}

Вывод:

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

В основном просто определяйте имена элементов node, которые закрываются самостоятельно, загружают всю строку html в библиотеку DOM, захватывают все элементы, перебирают и отфильтровывают те, которые не закрываются и не работают на них.

Я уверен, что вы уже знаете, что вам не следует использовать регулярное выражение для этой цели.

Ответ 14

Я не знаю вашей конкретной потребности в этом, но если вы также используете .NET, не могли бы вы использовать Html Agility Pack

Выдержки:

Это библиотека кода .NET, которая позволяет вы разбираете "вне Интернета" HTML файлы. Парсер очень толерантен с искаженным HTML-кодом "реального мира".

Ответ 15

Вам нужен первый >, которому не предшествует /. Посмотрите здесь для получения подробной информации о том, как это сделать. Он упоминается как негативный вид.

Однако наивная реализация этого приведет к совпадению <bar/></foo> в этом примере документа

<foo><bar/></foo>

Можете ли вы предоставить немного больше информации о проблеме, которую вы пытаетесь решить? Проигрываете ли вы программно с помощью тегов?

Ответ 16

W3C объясняет разбор в форме псевдо-регулярного выражения:
ссылка W3C

Следуйте за ссылками var для QName, S и Attribute, чтобы получить более четкое изображение.
Исходя из этого, вы можете создать довольно хорошее регулярное выражение для обработки таких вещей, как снятие тегов.

Ответ 17

Если вам нужно это для PHP:

PHP DOM функции не будут работать должным образом если он не был правильно отформатирован XML. Независимо от того, насколько лучше их использование для остальной части человечества.

simplehtmldom - это хорошо, но я нашел его немного багги, и он довольно большой в памяти [будет разбиваться на большие страницы. ]

Я никогда не использовал querypath, поэтому не могу комментировать его полезность.

Еще одна попытка - мой DOMParser, который очень легк для ресурсов, и я долгое время использовал. Простой в освоении и мощный.

Для Python и Java были опубликованы похожие ссылки.

Для downvoters - я написал свой класс только тогда, когда синтаксические анализаторы XML оказались не в состоянии противостоять реальному использованию. Религиозное downvoting просто препятствует тому, чтобы полезные ответы были отправлены - держите вещи в пределах перспективы вопроса, пожалуйста.

Ответ 18

Здесь решение:

<?php
// here 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 get the occurrences:
preg_match_all($pattern, $string, $matches, PREG_PATTERN_ORDER);

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

Чтобы проверить это глубоко, я ввел в теги автозапуска строки, например:

  • < hr/ >
  • < ш / >
  • < бр >

Я также ввел теги с помощью:

  • один атрибут
  • более одного атрибута
  • значение которого привязано либо в одинарные кавычки, либо в двойные кавычки
  • содержащие одинарные кавычки, когда разделителем является двойная кавычка и наоборот
  • "unpretty" с пробелом перед символом "=", после него и до и после него.

Если вы обнаружите что-то, что не работает в доказательстве концепции выше, я доступен для анализа кода, чтобы улучшить свои навыки.

< РЕДАКТИРОВАТЬ > Я забыл, что вопрос от пользователя заключался в том, чтобы избежать разбора самозакрывающихся тегов. В этом случае шаблон проще, превращаясь в это:

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

Пользователь @ridgerunner заметил, что шаблон не позволяет атрибуты без кавычек или без значения. В этом случае тонкая настройка приводит нас к следующему шаблону:

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

</РЕДАКТИРОВАТЬ >

Понимание шаблона

Если кто-то заинтересован узнать больше о шаблоне, я предоставляю некоторую строку:

  • первое подвыражение (\ w +) соответствует имени тега
  • второе подвыражение содержит шаблон атрибута. Он состоит из:
    • одно или несколько пробелов \s +
    • имя атрибута (\ w +)
    • ноль или более пробелов \s * (возможно или нет, оставляя пробелы здесь)
    • символ "="
    • снова, ноль или более пробелов
    • разделитель значения атрибута, одинарная или двойная кавычка ( "|" ). В шаблоне одиночная кавычка экранируется, потому что она совпадает с разделителем строки PHP. Это подвыражение захватывается круглыми скобками, поэтому можно снова ссылаться, чтобы разобрать закрытие атрибута, поэтому очень важно.
    • значение атрибута, соответствующее почти любому: (. *?); в этом конкретном синтаксисе, используя жадное соответствие (знак вопроса после звездочки), механизм RegExp включает в себя оператор "look-ahead", который соответствует чему угодно, но что следует за этим подвыражением
    • вот весело: the\4 part - это оператор backreference, который ссылается на подвыражение, определенное ранее в шаблоне, в данном случае я имею в виду четвертое подвыражение, который является первым разделителем атрибутов, найденным
    • ноль или более пробелов \s *
    • конец суб-выражения атрибута заканчивается здесь, с указанием нуля или более возможных вхождений, заданных звездочкой.
  • Затем, поскольку тег может заканчиваться пробелом перед " > ", символ, ноль или более пробелов сопоставляются с подшаблоном \s *.
  • Соответствующий тег может заканчиваться простым " > " символ или возможное закрытие XHTML, которое использует перед ним косую черту: (/" > | > ). Слэш, конечно, сбежал, поскольку он совпадает с разделителем регулярных выражений.

Небольшой совет: чтобы лучше проанализировать этот код, необходимо посмотреть исходный код, сгенерированный, так как я не предоставил никаких специальных символов HTML, которые могут быть экранированы.

Ответ 19

Всякий раз, когда мне нужно быстро извлечь что-то из HTML-документа, я использую Tidy, чтобы преобразовать его в XML, а затем использовать XPath или XSLT, чтобы получить то, что мне нужно. В вашем случае что-то вроде этого:

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

Ответ 20

Я использовал инструмент с открытым исходным кодом под названием HTMLParser. Он предназначен для разбора HTML по-разному и служит цели достаточно хорошо. Он может анализировать HTML как отличный treenode, и вы можете легко использовать его API для получения атрибутов из node. Проверьте это и посмотрите, поможет ли это вам.

Ответ 21

Мне нравится анализировать HTML с регулярными выражениями. Я не пытаюсь разбирать идиот HTML, который намеренно нарушен. Этот код является моим основным синтаксическим анализатором (Perl edition):

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

Он называется htmlsplit, разбивает HTML на строки, с одним тегом или фрагментом текста в каждой строке. Затем линии могут быть обработаны другими текстовыми инструментами и сценариями, такими как grep, sed, Perl и т.д. Я даже не шучу:) Наслаждайтесь.

Достаточно просто перегрузить мой slurp-all-first Perl script в приятную поточную передачу, если вы хотите обрабатывать огромные веб-страницы. Но это действительно не нужно.

Бьюсь об заклад, я заберусь для этого.

Разделение HTML


В противовес моему ожиданию, это получило некоторые обороты, поэтому я предлагаю несколько правильных выражений:

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

Они хороши для XML/XHTML.

С небольшими вариациями он может справиться с беспорядочным HTML... или сначала конвертировать HTML → XHTML.


Лучший способ писать регулярные выражения - это Lex/Yacc, а не как непрозрачные однострочные или прокомментированные многострочные чудовища. Я не делал этого здесь; эти им едва ли нужны.

Ответ 22

Вот парсер PHP на основе PHP, который анализирует HTML с использованием некоторого нечестивого регулярного выражения. Как автор этого проекта, я могу сказать вам, что можно анализировать HTML с регулярным выражением, но не эффективно. Если вам нужно решение на стороне сервера (как я сделал для моего wp-Typography WordPress plugin), это работает.

Ответ 23

Есть несколько хороших регулярных выражений для замены HTML на BBode здесь. Обратите внимание на то, что он не пытается полностью разобрать HTML, просто для его дезинфекции. Возможно, он может позволить себе убить теги, которые его простой "парсер" не может понять.

Например:

$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;

Ответ 24

Что касается методов RegExp для анализа (x) HTML, то ответ всем, кто говорил о некоторых ограничениях, заключается в следующем: вы недостаточно подготовлены, чтобы управлять силой этого мощного оружия, поскольку NOBODY здесь говорил о рекурсии.

Представитель RegExp-agnostic уведомил меня об этом обсуждении, которое, безусловно, не является первым в Интернете по этой старой и горячей теме.

После чтения некоторых сообщений первое, что я сделал, это поиск строки "? R" в этом потоке. Второй - поиск "рекурсии".
Нет, святая корова, совпадения не найдено.
Поскольку никто не упоминал о главном механизме, на котором построен парсер, я скоро понял, что никто не понял.

Если парсер (x) HTML нуждается в рекурсии, для этого недостаточно парсер RegExp без рекурсии. Это простая конструкция.

черное искусство RegExp трудно осваивать, поэтому, возможно, есть дополнительные возможности, которые мы оставили во время тестирования и тестирования нашего личного решения, чтобы захватить всю сеть в одной руке... Ну, я я уверен в этом:)

Здесь волшебный паттерн:

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

Просто попробуй. Он написан как строка PHP, поэтому модификатор "s" делает классы включающими символы новой строки.
Здесь примерная заметка в руководстве PHP, которую я написал в январе: Reference

(Позаботьтесь, в этой заметке я ошибочно использовал модификатор "m", его следует стереть, несмотря на то, что он был отброшен движком RegExp, поскольку не использовалось никакое ^ или $anchorage.)

Теперь мы можем говорить о границах этого метода с более информированной точки зрения:

  • в соответствии с конкретной реализацией механизма RegExp рекурсия может иметь ограничение в количестве вложенных шаблонов, обработанных, но зависит от используемого языка
  • хотя поврежденный (x) HTML не приводит к серьезным ошибкам, он не дезинфицирован.

Во всяком случае, это всего лишь шаблон RegExp, но он раскрывает возможность разработки множества мощных реализаций.
Я написал этот шаблон, чтобы включить рекурсивный синтаксический анализатор механизма шаблонов, который я построил в своей структуре, и производительность действительно велика, как во время выполнения, так и в использовании памяти (ничего общего с другими механизмами шаблонов, которые используют один и тот же синтаксис).

Ответ 25

Как уже отмечалось многими, HTML не является обычным языком, который может затруднить его синтаксический анализ. Мое решение состоит в том, чтобы превратить его в обычный язык, используя аккуратную программу, а затем использовать синтаксический анализатор XML для использования результатов. Для этого есть много хороших вариантов. Моя программа написана с использованием Java с библиотекой jtidy, чтобы превратить HTML в XML, а затем Jaxen в xpath в результат.

Ответ 26

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

Объясненные детали:

<: начальный символ

\s*: у него могут быть пробелы перед именем тега (уродливые, но возможные).

(\w+): теги могут содержать буквы и цифры (h1). Ну, \w также соответствует '_', но это не мешает, я думаю. Если любопытное использование ([a-zA-Z0-9] +) вместо этого.

[^/>]*: все, кроме > и /, до закрытия >

>: закрытие >

неродственного

И тем ребятам, которые недооценивают регулярные выражения, заявляя, что они только настолько сильны, как обычные языки:

a n ba n ba n который не является регулярным и даже не контекстным, может быть сопоставлен с ^(a+)b\1b\1$

Backreferencing FTW!

Ответ 27

Недавно я написал HTML-дезинфицирующее средство в Java. Он основан на смешанном подходе регулярных выражений и Java-коде. Лично я ненавижу регулярные выражения и его глупость (читаемость, ремонтопригодность и т.д.), Но если вы уменьшите объем своих приложений, это может соответствовать вашим потребностям. Во всяком случае, мой sanitizer использует белый список для HTML-тегов и черный список для некоторых атрибутов стиля.

Для вашего удобства я создал игровую площадку, чтобы вы могли проверить, соответствует ли код вашим требованиям: игровая площадка и код Java. Ваш отзыв будет оценен.

Существует небольшая статья, описывающая эту работу в моем блоге: http://roberto.open-lab.com

Ответ 28

Если вы просто пытаетесь найти эти теги (без амбиций синтаксического анализа), попробуйте это регулярное выражение:

/<[^/]*?>/g

Я написал его через 30 секунд и протестировал здесь: http://gskinner.com/RegExr/

Он соответствует типам тегов, о которых вы упоминали, игнорируя типы, которые вы сказали игнорировать.

Ответ 29

Мне кажется, вы пытаетесь сопоставить теги без "/" в конце. Попробуйте следующее:

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

Ответ 30

Верно, что при программировании обычно лучше использовать выделенные парсеры и API вместо обычных выражений при работе с HTML, особенно если точность имеет первостепенное значение (например, если ваша обработка может иметь последствия для безопасности). Однако я не отношусь к догматическому мнению о том, что разметка в стиле XML никогда не должна обрабатываться с помощью регулярных выражений. Бывают случаи, когда регулярные выражения являются отличным инструментом для работы, например, когда вы делаете одноразовые изменения в текстовом редакторе, исправляете поврежденные файлы XML или обрабатываете форматы файлов, которые выглядят как arent, а не XML. Есть некоторые проблемы, о которых нужно знать, но они не являются непреодолимыми или даже обязательно релевантными.

Простое регулярное выражение, подобное <([^>"']|"[^"]*"|'[^']*')*>, обычно достаточно хорошо, в тех случаях, о которых я только что упомянул. Это наивное решение, все рассмотренное, но оно корректно допускает символы unencoded > в значениях атрибутов. Если вы ищете, например, тег table, вы можете адаптировать его как </?table\b([^>"']|"[^"]*"|'[^']*')*>.

Просто для того, чтобы дать представление о том, как выглядело бы более "продвинутое" регулярное выражение HTML, следующая довольно респектабельная работа по эмуляции поведения браузера в реальном мире и алгоритму синтаксического анализа HTML5:

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

Ниже приведено довольно строгое определение тегов XML (хотя он не учитывает полный набор символов Unicode, разрешенных в именах XML):

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

Конечно, они не учитывают окружающий контекст и несколько краевых случаев, но даже такие вещи могут быть рассмотрены, если вы действительно хотели (например, путем поиска совпадений другого регулярного выражения).

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