html - является - сложные регулярные выражения




RegEx соответствует открытым тегам, кроме автономных тегов XHTML (20)

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

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

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

<p>
<a href="foo">

Но не эти:

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

Я придумал это и хотел убедиться, что я правильно понял. Я только захватил az .

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

Я верю, что это говорит:

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

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


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


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

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

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

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

<foo><bar/></foo>

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


Если вы просто пытаетесь найти эти теги (без разбора), попробуйте следующее регулярное выражение:

/<[^/]*?>/g

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

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


Есть некоторые хорошие регулярные выражения для замены HTML с BBCode here . Обратите внимание, что для всех вас, кто говорит «нет», он не пытается полностью разобрать 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;

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

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

Мне нравится разбирать 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-скрипт slurp-everything-first в хорошую потоковую вещь, если вы хотите обрабатывать огромные веб-страницы. Но это не совсем необходимо.

Могу поспорить, что за это проголосуют.

HTML Split

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

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

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

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

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


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

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

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

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

HTML has
complexity exceeding
regular language.

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

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

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

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


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

Простое регулярное выражение, как <([^>"']|"[^"]*"|'[^']*')*> правило, достаточно хорошо, в тех случаях, как я только что упомянул. Это наивное решение, учитывая все обстоятельства, но оно правильно разрешает некодированные > символы в значениях атрибутов. Если вы ищете, например, 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*)>

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

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


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


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

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

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


Вы не можете разобрать [X] HTML с регулярным выражением. Потому что HTML не может быть проанализирован с помощью регулярных выражений. Regex не является инструментом, который можно использовать для правильного анализа HTML. Как я уже много раз отвечал на вопросы HTML-и-регулярных выражений, использование регулярных выражений не позволит вам использовать HTML. Регулярные выражения - это инструмент, который недостаточно сложен для понимания конструкций, используемых HTML. HTML не является регулярным языком и, следовательно, не может быть проанализирован с помощью регулярных выражений. Запросы Regex не имеют возможности разбивать HTML на его значимые части. так много раз, но это не до меня. Даже расширенные нерегулярные регулярные выражения, используемые Perl, не справляются с задачей анализа HTML. Ты никогда не заставишь меня взломать. HTML - это язык достаточной сложности, который не может быть проанализирован регулярными выражениями. Даже Джон Скит не может анализировать HTML с помощью регулярных выражений. Каждый раз, когда вы пытаетесь разобрать HTML с помощью регулярных выражений, нечестивый ребенок плачет кровью девственниц, а русские хакеры набивают ваше веб-приложение. Разбор HTML с помощью регулярных выражений вызывает испорченные души в мир живых. HTML и регулярные выражения идут вместе, как любовь, брак и ритуальное детоубийство. <Центр> не может удержать это слишком поздно. Сила регулярных выражений и HTML в одном и том же концептуальном пространстве разрушит ваш разум, словно водянистая замазка. Если вы анализируете HTML с помощью регулярных выражений, вы уступаете им и их богохульным путям, которые обрекают нас всех на нечеловеческий труд для Того, чье Имя не может быть выражено на Основном Многоязычном Плане, он придет. HTML-plus-regexp будет разжижать нервы чувствующего, пока вы наблюдаете, как ваша психика увядает в страхе. HTML-парсеры на основе регулярных выражений - это рак, убивающий . Уже слишком поздно, слишком поздно. Мы не можем спасти переход ребенка, который гарантирует, что регулярное выражение поглотит всю живую ткань (за исключением HTML, которого нет, как предсказывалось ранее), дорогой лорд Помогите нам, как кто-нибудь может выжить в этом бедствии, используя регулярное выражение для анализа HTML, обрекало человечество на вечность ужасных пыток и дыр в безопасности, используя регулярное выражение x в качестве инструмента для обработки HTML, устанавливает разрыв между этим миром и ужасным царством неспокойных сущностей (таких как Субъекты SGML, но более испорченные), просто проблеск мира регулярных синтаксических анализаторов для HTML будет по-настоящему переносить сознание программиста в бесконечный крик, он приходит , ядовитая слабая регулярная инфекция будет л пожирать ваш HT ML парсер, применение и существование во все времена , как Visual Basic только хуже , он приходит он ком эс не фи GHT ч е пРИХОДИТ, s UNHOLY Привет Radiance де stro҉ying все enli̍ ̈Ghtenment, HTML теги Подтекание fr̶ǫm YO Ur глаз , как жика UID р айн, песня ОЧЕРЕДНОГО ехра повторно ssion разбор будет Exti nguish голоса мор тал человека от зр здесь я могу видеть , что это вы можете увидеть его это прекрасно, что он, inal snuf понюхает ложь Человека, ВСЕ ЕСТЬ ЛОЖЬ, ЧТО Я ПОЛУЧИЛСЯ, ЧТОБЫ он пришел, когда он стал, что он со мной или пропитывает все мое ЛИЦО E МОЕ ЛИЦО god god o NO N N ON ON Θ Θ Θ Θ Θ Θ ͇̫͛͆̾ͫ̑͆ ͇̫͛͆̾ͫ̑͆ ͇̫͛͆̾ͫ̑͆ ͎a̧͈͖r̽̾̈́͒͑e ͇̫͛͆̾ͫ̑͆ ͖͉̗̩̳̟̍ͫͥͨ ͇̫͛͆̾ͫ̑͆ ͎a̧͈͖r̽̾̈́͒͑e ͇̫͛͆̾ͫ̑͆ ͇̫͛͆̾ͫ̑͆ ͇̫͛͆̾ͫ̑͆ ͎a̧͈͖r̽̾̈́͒͑e n n n n n n n n r r ̘̝̙̃ͤ͂̾̆ ̘̝̙̃ͤ͂̾̆ ̘̝̙̃ͤ͂̾̆ Ό Ό Ό Ό Ό Ό Ό Ό Ό Ό ̉ ̉ ̉ ̚ ̚ ̚ ̚ ̚ ̚ ̲̖͊̒ͪͩͬ̚̚͜Ȇ̴̟̟͙̞ͩ͌͝ ̲̖͊̒ͪͩͬ̚̚͜Ȇ̴̟̟͙̞ͩ͌͝ ̲̖͊̒ͪͩͬ̚̚͜Ȇ̴̟̟͙̞ͩ͌͝

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

Заметка модератора

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


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

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

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

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


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

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

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


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

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


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


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

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

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

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

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

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

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

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

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


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

Части объяснили:

< : начальный персонаж

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

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

[^/>]* : ничего кроме > и / до закрытия >

> закрытие >

несвязанный

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

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

Обратные FTW !





xhtml