Regex заменить 2 записи в том же файле, не перезаписывая предыдущую замену регулярных выражений? [Дубликат]

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

<p>
<a href="foo">

Но не эти:

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

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

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

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

  • Найти меньше, чем [, g0]
  • Найти ( и захватить) az один или несколько раз, тогда
  • Найдите ноль или более пробелов, затем
  • Найдите любой символ ноль или более раз, жадный, кроме /, затем
  • Найти большее, чем

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

1324
задан 11 revs, 7 users 58% 26 May 2012 в 21:37
поделиться

30 ответов

Вы не можете разобрать 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̿̔̉x HTML-парсеры - это рак, который убивает StackOverflow, слишком поздно, что слишком поздно мы не можем спасти trangession of child, гарантирует, что регулярное выражение будет потреблять всю живую ткань (за исключением HTML, который он не может, как ранее пророчествовал) дорогой лорд помогите нам, как кто-либо сможет выжить в этом бедствии, используя регулярное выражение для анализа HTML, обрек человечество на вечность страшных пыток и дыр в безопасности, используя регулярное выражение в качестве инструмента для обработки HTML, устанавливает нарушение между этим миром и областью страха сущностных сущностей (например, SGML-сущностей , но более коррумпированный), простое представление о мире reg ex parsers для HTML будет вставлять , тантьё переносить сознание программиста в мир непрестанного крика, он приходит, зловонная слизистая регулярная инфекция wil l пожирайте ваш парсер, приложение и существование в HT ML на все время, например Visual Basic, только хуже, он приходит, не делает h e com̡e̶s, ̕h̵i s неудовлетворительное радианское разрушение все улучшения, HTML-теги lea͠ki̧n͘g fr̶ǫm ̡yo ͟ur eye͢s̸ ̛l̕ik͏e liq uid pain, песня reggular exp ression parsing будет распространять голоса mor tal man из sp здесь я вижу, что вы можете видеть, что это красиво. f inal snuf пальцы лжи s человека ALL IS LOŚ͖̩͇̗̪̏̈T A LL I SL OST pon̷y он приходит, он c̶̮omes он co mes the ich или пронизывает весь МОЙ ЛИЦ МОЙ ЛИЦО ᵒh god n o NO NOO̼ O ON Θ остановить a * ̶͑̾̾ ̅ͫ͏̙̤g͇̫͛͆̾ͫ̑͆l͖͉̗̩̳̟̍ͫͥͨe̠̅s ͎a̧͈͖r̽̾̈́͒͑e n ot rè̑ͧ̌aͨl̘̝̙ͤ̾̆ ZA̡͊͠͝LGΌ ISͮ҉̯͈͕̹̘ T O͇̹̺Ɲ̴ȳ̳ TH̘ Ë͖̉ ͠P̯͍̭O̚ N̐Y̡ H̸̡̪̯ͨ͊̽̅̾Ȩ̬̩̾͛ͪ̈͘ ̶̧̨̹̭̯ͧ̾ͬC̷̙̝͖ͭ̏ͥͮ͟Oͮ͏̮̪̝͍M̖͊̒ͪͩͬ̚̚͜Ȇ̴̟̟͙̞ͩ͌͝ S̨̥̫͎̭ͯ̿̔

< hr>

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


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

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

4422
ответ дан 7 revs, 5 users 36% 19 August 2018 в 11:16
поделиться
  • 1
    Коби: Думаю, мне пора уходить с должности помощника, а не анализировать HTML с офицером регулярных офицеров. Независимо от того, сколько раз мы это говорим, они не перестают приходить каждый день ... каждый час. Это потерянная причина, с которой кто-то может немного побороться. Итак, продолжайте, анализируйте HTML с регулярным выражением, если нужно. Это только сломанный код, а не жизнь и смерть. – bobince 14 November 2009 в 00:18
  • 2
    – Chris Porter 17 November 2009 в 19:26
  • 3
    Если вы не можете видеть это сообщение, вот скриншот его во всей красе: imgur.com/gOPS2.png – Andrew Keeton 19 November 2009 в 15:37

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

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

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

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

Я думаю, что 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 или полное регулярное выражение

455
ответ дан 11 revs, 9 users 71% 19 August 2018 в 11:16
поделиться
  • 1
    Господи, это массивно. Мой самый большой вопрос - почему? Вы понимаете, что на всех современных языках есть XML-парсеры, верно? Вы можете сделать все это как 3 строки и быть уверенным, что это сработает. Кроме того, вы также понимаете, что чистое регулярное выражение доказуемо неспособно делать определенные вещи? Если вы не создали гибридный regex / imperative code parser, но он не похож на вас. Можете ли вы также сжимать случайные данные? – Justin Morgan 8 March 2011 в 16:23
  • 2
    @Justin Мне не нужна причина. Это можно сделать (и это не было незаконным / безнравственным), поэтому я это сделал. Нет ограничений для ума, кроме тех, кого мы признаем (Наполеон Хилл) ... Современные языки могут анализировать XML? В самом деле? И я думал, что это незаконно! :-) – xanatos 8 March 2011 в 16:31
  • 3
    Сэр, я убежден. Я собираюсь использовать этот код как часть ядра для своей машины с вечным движением - можете ли вы поверить, что эти дураки в патентном ведомстве продолжают отклонять мое заявление? Хорошо, я покажу им. Я покажу им всех! – Justin Morgan 8 March 2011 в 18:55
  • 4
    @Justin Итак, Xml Parser по определению является ошибкой, а Regex - нет? Поскольку, если Xml Parser не является ошибкой по определению, может быть xml, из-за которого он падает, и мы вернемся к шагу 0. Скажем так: и Xml Parser, и это Regex попытаются разобрать все & quot; правовой & Quot; XML. Они могут анализировать некоторые "незаконные" XML. Ошибки могут сбить их обоих. C # XmlReader, безусловно, более проверен, чем это Regex. – xanatos 9 March 2011 в 16:08
  • 5
    Нет, без ошибок нет: 1) Все программы содержат хотя бы одну ошибку. 2) Все программы содержат по крайней мере одну строку ненужного исходного кода. 3) В # 1 и # 2 и используя логическую индукцию, просто доказать, что любая программа может быть сведена к одной строке кода с ошибкой. (от обучения Perl) – sweaver2112 16 February 2012 в 02:53
<?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"

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

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

154
ответ дан 2 revs 19 August 2018 в 11:16
поделиться
  • 1
    Если вы имеете дело с реальным XHTML, добавьте getElementsByTagName с NS и укажите пространство имен. – meder omuraliev 15 November 2009 в 15:39

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

//p/a[@href='foo']
90
ответ дан 2 revs, 2 users 67% 19 August 2018 в 11:16
поделиться

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

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

<foo><bar/></foo>

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

133
ответ дан 2 revs, 2 users 89% 19 August 2018 в 11:16
поделиться
  • 1
    Да, конечно. Определение всех тегов, которые в настоящее время открыты, а затем сравнить их с закрытыми тегами в отдельном массиве. RegEx болит мой мозг. – Jeff 14 November 2009 в 00:04

W3C объясняет разбор в форме псевдорежима: W3C Link

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

122
ответ дан 2 revs, 2 users 92% 19 August 2018 в 11:16
поделиться

Сунь Цзы, древний китайский стратег, генерал и философ, сказал:

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

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

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

HTML has
complexity exceeding
regular language.

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

The regex you seek
is defined within the phrase
<([a-zA-Z]+)(?:[^>]*[^/]*)?>
165
ответ дан 2 revs, 2 users 98% 19 August 2018 в 11:16
поделиться

Попробуйте:

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

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

177
ответ дан 3 revs, 2 users 77% 19 August 2018 в 11:16
поделиться
  • 1
    & lt; a href = "foo" название = & Quot; 5 & GT; 3 & Quot; & GT; Oops & lt; / a & gt; – Gareth 14 November 2009 в 00:11
  • 2
    Это очень верно, и я подумал об этом, но я предположил, что символ > правильно экранирован до & amp; gt ;. – Kobi 14 November 2009 в 00:16
  • 3
    > действителен в значении атрибута. Действительно, в сериализации «канонического XML» вы не должны использовать &gt;. (Это не совсем актуально, за исключением того, что > в значении атрибута вовсе не является чем-то необычным). – bobince 14 November 2009 в 01:15
  • 4
    @Kobi: что восклицательный знак (тот, который вы поставили в конце) означает в регулярном выражении? – Marco Demaio 30 April 2011 в 18:16
  • 5
    @bobince: Уверены ли вы? Я больше не понимаю, так же верно и HTML: <div title="this tag is a <div></div>">hello</div> – Marco Demaio 30 April 2011 в 18:31

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

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

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

55
ответ дан 3 revs, 3 users 64%Roberto 19 August 2018 в 11:16
поделиться
  • 1
    Ваши ссылки мертвы, и на самом деле это не дает никакого полезного ответа. – kenorb 19 May 2015 в 16:23

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

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

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

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

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

Вот волшебный паттерн:

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

Просто попробуйте. Он написан как строка PHP, поэтому модификатор «s» делает классы include новыми. Вот пример заметки в руководстве по PHP, которое я написал в январе: Ссылка

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

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

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

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

66
ответ дан 3 revs, 3 users 75% 19 August 2018 в 11:16
поделиться
  • 1
    Я поставлю это в «Regex», который не позволяет больше, чем в атрибутах ». бен. Проверьте его на & lt; входное значение = & lt; 5 & gt; 3 & Quot; / & GT; – Gareth 5 July 2010 в 17:24
  • 2
    Если вы поместите что-то подобное в производственный код, скорее всего, вас застрелит сопровождающий. Жюри никогда не осуждало его. – aehiilrs 5 July 2010 в 17:33
  • 3
    Регулярные выражения не могут работать, потому что по определению они не являются рекурсивными. Добавление рекурсивного оператора к регулярным выражениям в основном делает CFG только с более слабым синтаксисом. Почему бы не использовать что-то, предназначенное для рекурсивного в первую очередь, а не насильно вставить рекурсию во что-то уже переполненное посторонними функциями? – Welbog 6 July 2010 в 19:38
  • 4
    Мое возражение - это не одна из функциональных возможностей, которую он вложил вовремя. Проблема с RegEx заключается в том, что к тому моменту, когда вы публикуете маленькие слоты cutsey, кажется, что вы сделали что-то более эффективно («См. Одну строку кода!»). И, конечно же, никто не упоминает полчаса (или 3), которое они провели со своим чит-листом и (надеюсь), проверяя каждую возможную перестановку ввода. И как только вы преодолеете все это, когда сопровождающий выясняет или проверяет код, он не может просто взглянуть на него и убедиться, что он прав. Им приходится анализировать выражение и, в сущности, повторять его снова и снова ... – Oorang 10 July 2010 в 16:11
  • 5
    ... знать, что это хорошо. И это произойдет даже с людьми, которые good с регулярным выражением. И, честно говоря, я подозреваю, что подавляющее большинство людей не будет знать это хорошо. Таким образом, вы берете один из самых печально известных кошмаров для обслуживания и сочетаете его с рекурсией, которая является кошмаром обслуживания other , и я думаю, что мне действительно нужно, чтобы мой проект был немного менее умным. Цель состоит в том, чтобы написать код, который могут поддерживать плохие программисты, не нарушая базы кода. Я знаю, что это галлы для кодирования наименее общего знаменателя. Но наем отличного таланта тяжелый, и вы часто ... – Oorang 10 July 2010 в 16:17

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

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

simplehtmldom хорош, но я нашел его немного ошибкой, и он довольно тяжелый для памяти [Will crash на больших страницах.]

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

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

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

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

105
ответ дан 4 revs, 2 users 98% 19 August 2018 в 11:16
поделиться

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

255
ответ дан 4 revs, 4 users 57% 19 August 2018 в 11:16
поделиться
  • 1
    @ Kyle-jQuery не анализирует XML, он использует встроенный парсер клиента (если он есть). Поэтому вам не нужен jQuery для этого, но всего лишь две строки обычного старого JavaScript . Если встроенный парсер отсутствует, jQuery не поможет. – RobG 31 October 2013 в 08:25
  • 2
    @RobG На самом деле jQuery использует DOM, а не встроенный синтаксический анализатор. – Qix 22 September 2014 в 04:49
  • 3
    @ Qix-вы бы лучше сказали авторам документации: « jQuery.parseXML использует встроенную функцию синтаксического разбора браузера ... ». Источник: jQuery.parseXML () – RobG 22 September 2014 в 06:01
  • 4
    Придя сюда из вопроса meme ( meta.stackexchange.com/questions/19478/the-many-memes-of-meta/… ), мне нравится, что одним из ответов является «Использовать jQuery ' – Jorn 1 April 2016 в 21:09

Есть несколько хороших регулярных выражений для замены HTML с помощью BBCode здесь . Обратите внимание на то, что он не пытается полностью разобрать 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;
69
ответ дан 4 revs, 4 users 88% 19 August 2018 в 11:16
поделиться

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

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

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

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

Думаю, чтобы он не соответствовал самодостаточным тегам, вы либо захотите использовать Kobi :

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

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

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

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

1020
ответ дан 5 revs, 2 users 92% 19 August 2018 в 11:16
поделиться
  • 1
    – prajeesh kumar 10 May 2012 в 04:44
  • 2
    Кто-то использует CDATA внутри HTML? – Danubian Sailor 2 March 2013 в 09:51
  • 3
    поэтому вы фактически не решаете проблему синтаксического анализа только с помощью регулярного выражения, но в качестве части анализатора это может работать. PS: рабочий продукт не означает хороший код. Не обижайтесь, но это то, как работает промышленное программирование и получает деньги – mishmashru 19 April 2013 в 13:18
  • 4
    Ваше регулярное выражение перестает работать с самым коротким, допустимым HTML: <!doctype html><title><</title>. Простой '<!doctype html><title><</title>'.match(/<(?:"[^"]*"['"]*|'[^']*'['"]*|[^'">])+>/g) возвращает ["<!doctype html>", "<title>", "<</title>"], а ["<title>", "</title>"]. – Benio 1 May 2014 в 17:48
  • 5
    Что такое «пропутчик пропуска», – Richard de Wit 3 June 2015 в 14:07

Мне нравится анализировать HTML с регулярными выражениями. Я не пытаюсь разбирать идиот HTML, который намеренно нарушен. Этот код является моим основным парсером (версия 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

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

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

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

HTML Split


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

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

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

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


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

84
ответ дан 5 revs, 3 users 69% 19 August 2018 в 11:16
поделиться
  • 1
    «Я не пытаюсь разбирать идиот HTML, который намеренно нарушен». Как ваш код знает разницу? – Kevin Panko 26 July 2011 в 21:38
  • 2
    Ну, это не имеет большого значения, если HTML сломан или нет. Вещь по-прежнему будет разделять HTML на теги и текст. Единственное, что может испортить это, - это если люди включают unescaped & lt; или & gt; символов в тексте или атрибутах. На практике мой крошечный сплиттер HTML работает хорошо. Мне не нужен огромный монстр, полный эвристики. Простые решения не для всех ...! – Sam Watkins 8 March 2012 в 05:22
  • 3
    Я добавил несколько простых регулярных выражений для извлечения тегов, текста и атрибутов для XML / XHTML. – Sam Watkins 22 May 2012 в 09:00
  • 4
    (получить атрибут 1) /(\w+)="(.*?)"/ предполагает двойные кавычки. Он будет пропускать значения в одинарных кавычках. В html версии 4 и ранее некотированное значение разрешено, если это простое слово. – David Andersson 11 September 2016 в 08:23
  • 5
    (получить атрибут bug 2) /(\w+)="(.*?)"/ может ложно соответствовать тексту, который выглядит как атрибут внутри атрибута, например. <img title="Nope down='up' for aussies" src="..." />. Если он применяется глобально, он также будет соответствовать таким вещам в обычном тексте или в комментариях html. – David Andersson 11 September 2016 в 08:28
<\s*(\w+)[^/>]*>

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

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

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

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

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

>: закрытие >

UNRELATED

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

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

Обратное обращение FTW !

59
ответ дан 5 revs, 4 users 73% 19 August 2018 в 11:16
поделиться
  • 1
    @GlitchMr, это был его смысл. Современные регулярные выражения не являются технически регулярными, и нет никаких причин для их возникновения. – alanaktion 2 February 2013 в 17:45
  • 2
    @alanaktion: «Современный» регулярные выражения (read: с расширениями Perl) не могут совпадать внутри O(MN) (M - длина регулярного выражения, N - длина текста). Backreferences - одна из причин этого. Реализация в awk не имеет обратных ссылок и соответствует всем в течение O(MN) времени. – Konrad Borowski 14 February 2013 в 18:52

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

/<[^/]*?>/g

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

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

84
ответ дан 6 revs, 2 users 96% 19 August 2018 в 11:16
поделиться
  • 1
    Не соответствует действительным тегам, имеющим атрибуты без значения, т. Е. <option selected>. Также не соответствует действительным тегам с значениями без кавычек, т. Е. <p id=10>. – ridgerunner 25 July 2011 в 16:01
  • 2
    @ridgerunner: Большое спасибо за ваш комментарий. В этом случае шаблон должен немного измениться: $ pattern = '/<(\w+)(\s+(\w+)(\s*\=\s*(\'|"|)(.*?) \\ 5 \ s *)) * \ s * & GT;? / '; Я тестировал его и работал в случае не цитируемых атрибутов или атрибутов без значения. – Emanuele Del Grande 25 July 2011 в 17:41
  • 3
    Как насчет пробела перед именем тега: < a href="http://wtf.org" > Я уверен, что это законно, но вы не соответствуете ему. – Floris 5 October 2013 в 05:58
  • 4
    Нет, извините, пробелы перед тэгом являются незаконными. Помимо того, что он «довольно уверен». почему бы вам не дать какие-либо доказательства вашего возражения? Вот мои, w3.org/TR/xml11/#sec-starttags , относящиеся к XML 1.1, и вы можете найти то же самое для HTML 4, 5 и XHTML, поскольку валидация W3C также предупреждает, если вы делаете тест. Как и многие другие бла-бла-поэты здесь, я еще не получал разумных аргументов, кроме нескольких сотен минус моих ответов, чтобы продемонстрировать, где мой код терпит неудачу в соответствии с правилами контракта указанных в вопросе. Я только приветствовал бы их. – Emanuele Del Grande 6 October 2013 в 19:03
  • 5
    @ridgerunner, конечно, ваш комментарий был умным и приветливым. – Emanuele Del Grande 6 October 2013 в 19:09
  • 6
    Я думаю, вы имеете в виду \/> вместо \\>. – Justin Morgan 19 December 2014 в 18:36
  • 7
    Нет, просто \> - это то, что я имел в виду; Я никогда не хотел редактировать регулярное выражение моего оригинального сообщения. – Lonnie Best 29 May 2016 в 06:38
  • 8
    FYI, вам не нужно скрывать угловые скобки. Конечно, в любом случае, это не вредит побегу, но посмотрите на путаницу, которую вы могли бы избежать. ;) – Alan Moore 29 May 2016 в 07:47
  • 9
    Я иногда избегаю ненужного, когда я не уверен, что что-то особенное или нет. Я отредактировал ответ; он работает так же, но более кратким. – Lonnie Best 31 May 2016 в 07:23
  • 10
    Глядя на это сейчас, я не знаю, почему я думал, что вы имеете в виду \/, поскольку это будет делать совершенно противоположное требованиям. Возможно, я думал, что вы предлагаете отрицательный шаблон фильтра. – Justin Morgan 1 June 2016 в 19:14
  • 1
    ОП просит разобрать очень ограниченное подмножество XHTML: начальные теги. Что делает (X) HTML CFG своим потенциалом иметь элементы между стартовыми и конечными тегами других элементов (как в правиле грамматики A -> s A e). (X) HTML not имеет это свойство внутри стартового тега: начальный тег не может содержать другие стартовые теги. Подмножество, которое ОП пытается разобрать, не является CFG. – LarsH 2 March 2012 в 10:43
  • 2
    В теории CS регулярные языки являются строгим подмножеством неконтекстно-свободных языков, но реализация на регулярном выражении в основных языках программирования более эффективна. Поскольку noulakaz.net/weblog/2007/03/18/… описывает так называемые «регулярные выражения», может проверять простые числа в унарном, что, безусловно, является чем-то, что не может выполнить регулярное выражение из теории СС. – Adam Mihalcin 20 March 2012 в 01:50
  • 3
    @eyelidlessness: тот же "только если" относится ко всем CFG, не так ли? То есть если вход HTML (X) не является корректным, даже полноценный анализатор XML не будет работать надежно. Возможно, если вы дадите примеры синтаксических ошибок «(X) HTML, реализованных в реальных агентах реального мира») вы имеете в виду, я пойму, что вы получаете лучше. – LarsH 22 May 2012 в 06:09
  • 4
    @AdamMihalcin в точности прав. Большинство существующих регулярных выражений более мощные, чем грамматики типа Хомского типа 3 (например, нежелательное совпадение, backrefs). Некоторые двигатели регулярных выражений (например, Perl) завершают Turing. Это правда, что даже те, которые являются плохими инструментами для синтаксического анализа HTML, но этот часто цитируемый аргумент не является причиной. – dubiousjim 31 May 2012 в 14:44
  • 5
    Это самый "полный и короткий" ответьте здесь. Это заставляет людей изучать основы формальных грамматик и языков и, надеюсь, некоторые математики, чтобы они не теряли времени на безнадежные вещи, такие как решение NP-задач в полиномиальное время – mishmashru 19 April 2013 в 13:15
2927
ответ дан 8 revs, 8 users 40% 19 August 2018 в 11:16
поделиться

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

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

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

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

1171
ответ дан 9 revs 19 August 2018 в 11:16
поделиться
  • 1
    Divison на ноль - гораздо более легкая проблема, чем другие, о которых вы говорите. Если вы используете интервалы, вместо простой арифметики с плавающей запятой (которой все должны быть, но никто не является), вы можете с радостью разделить что-то на [с интервалом, содержащим] ноль. Результат - это просто интервал, содержащий плюсы и минус бесконечность. – rjmunro 14 June 2012 в 11:53
  • 2
    Небольшая проблема Fermat была решена с помощью мягких полей в современном текстовом редакторе. – kd4ttc 1 March 2013 в 22:24
  • 3
    Рендалл Мунро решил проблему с малым запасом Ферма, установив значение fontsize равным нулю: xkcd.com/1381 – heltonbiker 16 October 2014 в 20:55
  • 4
    FYI: проблема Ферма была фактически решена в 1995 году , и для этого потребовались только 358 лет математикам. – jmiserez 22 January 2015 в 19:40
  • 5
    Я смог обойти этот липкий шаг деления на нуль, вместо этого использовал броуновские трещотки, полученные от холодного слияния ... хотя он работает только тогда, когда я удаляю космологическую константу. – Tim Lehner 9 March 2016 в 19:52

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


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

285
ответ дан 9 revs, 5 users 65% 19 August 2018 в 11:16
поделиться
  • 1
  • 2
    Боюсь, вы не получили шутку, @kenorb. Пожалуйста, прочитайте вопрос и принятый ответ еще раз. Речь идет не о инструментах разбора HTML в целом, ни об анализе инструментов оболочки HTML, а о разборе HTML с помощью регулярных выражений. – Palec 13 October 2015 в 08:12
  • 3
    @Palec Я тоже не получаю шутку. Разве почти невозможно разобрать HTML с регулярным выражением? – Abdul 24 March 2017 в 12:49
  • 4
    Да, этот ответ подводит итог этому, @ Abdul. Обратите внимание, что, однако, реализации регулярных выражений на самом деле не являются регулярными выражениями в математическом смысле - у них есть конструкции, которые делают их более сильными, часто Тьюринг-полными (эквивалентными грамматикам типа 0). Аргумент нарушается с этим фактом, но все еще несколько действителен в том смысле, что регулярные выражения никогда не были предназначены для выполнения такой работы. – Palec 24 March 2017 в 15:24
  • 5
    И, кстати, анекдот, о котором я говорил, был содержанием этого ответа перед изменениями кенорба (радикальными), в частности, версией 4, @Abdul. – Palec 24 March 2017 в 15:26

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

61
ответ дан Corey Sanders 19 August 2018 в 11:16
поделиться

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

Существует окончательное сообщение в блоге о совпадении сокровенных HTML-элементов, написанных Стивеном Левитаном.

48
ответ дан Emre Yazici 19 August 2018 в 11:16
поделиться

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

Выдержка:

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

149
ответ дан GONeale 19 August 2018 в 11:16
поделиться

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

73
ответ дан kingjeffrey 19 August 2018 в 11:16
поделиться
  • 1
    htmlawed - это еще один проект PHP, который анализирует HTML для фильтрации, преобразования и т. д. Имеет хороший код, если вы можете это понять! – user594694 12 May 2011 в 20:22
  • 2
    Нет, вы не можете анализировать HTML с регулярным выражением. Но для некоторых подмножеств это может работать. – mirabilos 5 December 2014 в 18:07

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

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

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

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

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

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

.NET Regular Expression Двигатель

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

  • (?<group>) - выталкивает захваченный результат в стек захвата с помощью группы имен.
  • (?<-group>) - отображает верхний захват с группой имен с захвата stack.
  • (?(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>

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

261
ответ дан Macro Man 19 August 2018 в 11:16
поделиться
  • 1
    System.Text не является частью C #. Это часть .NET. – John Saunders 2 February 2012 в 21:07
  • 2
    В первой строке вашего регулярного выражения ((?=<ul\s*id="matchMe"\s*type="square"\s*>) # match start with <ul id="matchMe"...) между "& lt; ul" и "id" должен быть \s+, а не \s*, если вы не хотите, чтобы он соответствовал & lt; ulid = ...;) – C0deH4cker 6 July 2012 в 03:49
  • 3
    @ C0deH4cker Вы правы, выражение должно иметь \s+ вместо \s*. – Sam 6 July 2012 в 23:33
  • 4
    Не то, чтобы я действительно это понял, но я думаю, что ваше регулярное выражение не срабатывает <img src="images/pic.jpg" /> – Scheintod 27 September 2013 в 18:05
  • 5
    @Scheintod Спасибо за комментарий. Я обновил код. Предыдущее выражение не удалось для самозакрывающихся тегов, у которых было / где-то внутри, что не удалось для вашего <img src="images/pic.jpg" /> html. – Sam 27 September 2013 в 20:00

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

<([a-zA-Z][a-zA-Z0-9]*)[^>]*(?<!/)>
52
ответ дан manixrock 19 August 2018 в 11:16
поделиться
  • 1
    Это не работает. Для ввода «& lt; x a =» & lt; b & gt; & gt; & lt; y & gt; совпадения - это x и y, хотя x завершается. – ceving 4 May 2011 в 17:33

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

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

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

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

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

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

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

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

213
ответ дан moritz 19 August 2018 в 11:16
поделиться
  • 1
    +1 за то, что речь идет не о разборе полного (X) HTML, а о сопоставлении (X) HTML открытых тегов. – LarsH 8 September 2012 в 03:26
  • 2
    Кое-что еще большинство ответов, похоже, игнорируют, заключается в том, что парсер HTML может очень хорошо использовать регулярные выражения в своей реализации для частей HTML, и я был бы удивлен, если большинство парсеров этого не сделали. – Thayne 26 March 2015 в 20:15
  • 3
    @Thayne Точно. При анализе отдельных тегов регулярное выражение является правильным инструментом для задания. Очень смешно, что нужно прокручивать половину страницы, чтобы найти разумный ответ. Принимаемый ответ неверен, поскольку он смешивает лексирование и синтаксический анализ. – kasperd 22 November 2015 в 11:26
  • 4
  • 5
    Это будет неправильно работать с HTML, содержащим комментарии или разделы CData. Он также будет работать неправильно, если цитируемый атрибут содержит символ >. Я согласен с тем, что OP предлагает can сделать с регулярным выражением, но представленная здесь далека от упрощения. – JacquesB 30 July 2017 в 10:14

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

90
ответ дан wen 19 August 2018 в 11:16
поделиться

Вот решение:

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

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

  1. & lt; hr / & gt;
  2. & lt; br / & gt;
  3. & lt; br & gt;

Я также вводил теги с:

  1. один атрибут
  2. содержит более одного атрибута
  3. , значение которого привязано либо в одинарные кавычки, либо в двойные кавычки
  4. атрибуты, содержащие одинарные кавычки, когда разделитель является двойным цитата и наоборот
  5. «нечеткие» атрибуты с пробелом перед символом «=» после него и до и после него.

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

& lt; EDIT & gt; Я забыл, что вопрос от пользователя заключался в том, чтобы избежать разбора самозакрывающихся тегов. В этом случае шаблон проще, превратившись в это:

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

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

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

& lt; / EDIT & gt;

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

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

  1. первое подвыражение (\ w +) соответствует имени тега
  2. , второе подвыражение содержит шаблон атрибут. Он состоит из: одного или нескольких пробелов \ s + имя атрибута (\ w +) ноль или более пробелов \ s * (возможно или нет, оставляя здесь пробелы) символ "=" снова, ноль или более пробелов разделитель значения атрибута, одинарная или двойная кавычка («|»). В шаблоне одиночная кавычка экранируется, потому что она совпадает с разделителем строки PHP. Это подвыражение захватывается скобками, поэтому на него можно ссылаться снова для синтаксического анализа закрытия атрибута, поэтому очень важно значение атрибута, сопоставляемое почти : (. *?); в этом конкретном синтаксисе, используя жадное соответствие ( вопросительный знак после звездочки), механизм RegExp позволяет использовать оператор «look-ahead», который соответствует чему-либо, но что следует за этим подвыражением, здесь весело: элемент \ 4 является оператором обратной ссылки, который ссылается на подзадачу, выражение, определенное ранее в шаблоне, в данном случае я имею в виду четвертое подвыражение, которое является первым a ttribute delimiter обнаружен ноль или более пробелов \ s * конец суб-выражения атрибута заканчивается здесь, с указанием нуля или более возможных вхождений, заданных звездочкой.
  3. Затем, поскольку тег может заканчиваться пробелом перед «& gt;», символ, ноль или более пробелов сопоставляются с подшаблоном \ s *.
  4. Тег, который должен соответствовать, может заканчиваться простым «& gt;» символ или возможное закрытие XHTML, которое использует перед ним косую черту: (/> |>). Слэш, конечно, сбежал, поскольку он совпадает с разделителем регулярных выражений.

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

84
ответ дан 6 revs, 2 users 96% 19 August 2018 в 11:16
поделиться
  • 1
    Не соответствует действительным тегам, имеющим атрибуты без значения, т. Е. <option selected>. Также не соответствует действительным тегам с значениями без кавычек, т. Е. <p id=10>. – ridgerunner 25 July 2011 в 16:01
  • 2
    @ridgerunner: Большое спасибо за ваш комментарий. В этом случае шаблон должен немного измениться: $ pattern = '/<(\w+)(\s+(\w+)(\s*\=\s*(\'|"|)(.*?) \\ 5 \ s *)) * \ s * & GT;? / '; Я тестировал его и работал в случае не цитируемых атрибутов или атрибутов без значения. – Emanuele Del Grande 25 July 2011 в 17:41
  • 3
    Как насчет пробела перед именем тега: < a href="http://wtf.org" > Я уверен, что это законно, но вы не соответствуете ему. – Floris 5 October 2013 в 05:58
  • 4
    Нет, извините, пробелы перед тэгом являются незаконными. Помимо того, что он «довольно уверен». почему бы вам не дать какие-либо доказательства вашего возражения? Вот мои, w3.org/TR/xml11/#sec-starttags , относящиеся к XML 1.1, и вы можете найти то же самое для HTML 4, 5 и XHTML, поскольку валидация W3C также предупреждает, если вы делаете тест. Как и многие другие бла-бла-поэты здесь, я еще не получал разумных аргументов, кроме нескольких сотен минус моих ответов, чтобы продемонстрировать, где мой код терпит неудачу в соответствии с правилами контракта указанных в вопросе. Я только приветствовал бы их. – Emanuele Del Grande 6 October 2013 в 19:03
  • 5
    @ridgerunner, конечно, ваш комментарий был умным и приветливым. – Emanuele Del Grande 6 October 2013 в 19:09
Другие вопросы по тегам:

Похожие вопросы: