Как сопоставить текст в HTML, который не находится внутри тегов?


8

Учитывая строку, как это:

<a href="http://blah.com/foo/blah">This is the foo link</a> 

... и строка поиска, как «Foo», я хотел бы выделить все вхождения «Foo» в тексте HTML - но не внутри тег. Другими словами, я хочу, чтобы получить это:

<a href="http://blah.com/foo/blah">This is the <b>foo</b> link</a> 

Однако, простой поиск и замену не будет работать, потому что она будет соответствовать часть URL в < а> HREF тега.

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

Примечание: Я обещаю, что HTML в вопросе не будет ничего патологического не будет так:

<img title="Haha! Here are some angle brackets to screw you up: ><" /> 

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

Редактировать 2: Опять же, я знаю, что Template :: Refine :: Fragment может анализировать весь мой HTML-код для меня. Если бы я писал приложение , я бы наверняка использовал такое решение. Но это не приложение. Это всего лишь сценарий оболочки. Это кусок одноразового кода. В этом случае большая часть автономного файла, который может быть передан, имеет большое значение. «Эй, запустите эту программу» - это гораздо более простая инструкция, чем: «Эй, установите модуль Perl, а затем запустите это ... подождите, что вы раньше никогда не использовали CPAN? Хорошо, запустите perl -MCPAN -e оболочку (желательно как root), а затем он задаст вам кучу вопросов, но на самом деле вам не нужно отвечать на них. Нет, не бойтесь, это ничего не сломает. Послушайте, вам не нужно чтобы ответить на каждый вопрос, - просто нажмите Enter и снова. Нет, я обещаю, это ничего не сломает.

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

Так что в то время как Template :: Refine :: Фрагмент может быть ответом на чужой HTML-анализ вопроса, это не ответ на вопрос этот вопрос. Я просто хочу, чтобы регулярное выражение работало на очень ограниченном подмножестве HTML, и скрипт действительно попросил разобрать.

10

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

s%(>|\G)([^<]*?)($key)%$1$2<b>$3</b>%g 
+1

Правда ... это часть того, почему другие говорят, что вы действительно должны использовать парсер HTML, а не простое регулярное выражение. И я на самом деле соглашаюсь с ними, но если вы действительно хотите использовать s ///, то выбивайте себя ;-) 22 фев. 092009-02-22 04:30:22

  0

Все они сломаны.Попробуйте выделить «foo» в «foo <blafoo> foo blabla foo \ n fooo</foo>« 22 фев. 092009-02-22 04:36:53

  0

Переосмыслить колесо так весело! 22 фев. 092009-02-22 04:43:42

  0

Теперь это интересно, принятый ответ с -3 голосами ... Я должен был удалить его :-( 22 фев. 092009-02-22 05:20:30

  0

@ Vlad: Спасибо за тестовый пример - но опять же я сам создаю HTML. У него может быть только один из несколько небольших форм, и это не один из них. Тем не менее, я обновил регулярное выражение, чтобы обработать ваш тестовый пример. 22 фев. 092009-02-22 05:37:50

  0

@raldi: Я стою исправлено. 22 фев. 092009-02-22 06:05:02

  0

Голосовали: это дерьмо, чтобы проголосовать за кого-то за попытку ответьте на вопрос OP, как хочет OP. Да, вы можете подумать, что он изобретает колесо, и все знают, что вы не можете написать полный, правильный HTML-парсер с регулярным выражением. Но OP хочет, что хочет (и имеет причины). Нет смысла пинать Дэвида. 22 фев. 092009-02-22 12:29:53

  0

Спасибо за поддержку ;-) (я дал вам случайный рейтинг для этого комментария) 22 фев. 092009-02-22 12:54:40

  0

(\ G |>) достаточно; pos() сбрасывается при запуске s /// g. 22 фев. 092009-02-22 18:55:19


7

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

#!/usr/bin/env perl 

use strict; 
use warnings; 
use feature ':5.10'; 

use Template::Refine::Fragment; 

my $frag = Template::Refine::Fragment->new_from_string('<p>Hello, world. <a href="http://foo.com/">This is a test of foo finding.</a> Here is another foo.'); 

say $frag->process(
    simple_replace { 
     my $n = shift; 
     my $text = $n->textContent; 
     $text =~ s/foo/<foo>/g; 
     return XML::LibXML::Text->new($text); 
    } '//text()', 
)->render; 

Это выходы:

<p>Hello, world. <a href="http://foo.com/">This is a test of &lt;foo&gt; finding.</a> Here is another &lt;foo&gt;.</p> 

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

Редактирование: наконец, если вы создаете HTML внутри своей программы, и вам нужно делать такие преобразования в строках, «UR DOIN IT WRONG». Вы должны построить DOM и только сериализовать его, когда все будет преобразовано.(. Вы можете использовать TR, однако, через new_from_dom конструктор)

  0

Хорошо, но я Автогенераторный все HTML (1?). Это чрезвычайно простой HTML. Я не могу добросовестно оправдывать привлечение всей супертяжелой библиотеки, чтобы просто ударить жирным тегам вокруг нескольких строк. 22 фев. 092009-02-22 04:17:59

  0

Делай, что хочешь. Мое время не потрачено впустую, когда вы изобретаете квадратное колесо. (Анализ HTML с помощью регулярных выражений очень затруднительный. Как показывают ваши примеры, это трудно понять.) 22 фев. 092009-02-22 04:24:23

  0

Регулярные ошибки не работают при рассмотрении комментариев и разделов CDATA. (синтаксические анализаторы на основе Regex прекрасны, но вам нужно сохранить больше состояний, чем regexes может хранить отдельно. Вот почему у вас есть синтаксический анализатор вместо случайного регулярного выражения .) 22 фев. 092009-02-22 04:42:36

  0

Я сам создаю HTML. В нем нет комментариев или разделов CDATA. Сценарий - 25 строк. Я не собираюсь добавлять зависимость от внешнего файла - то, что вы предлагаете, - это определение overengineering. 22 фев. 092009-02-22 05:26:59

  0

Но вы видите, я уже сделал для вас технику. Повторное использование ... вы слышали об этом? 22 фев. 092009-02-22 05:30:13

  0

Bloat: Вы слышали об этом? 22 фев. 092009-02-22 05:32:18

  0

Глупо взад-вперед: слышали ли вы об этом? 22 фев. 092009-02-22 05:34:40

  0

http://xkcd.com/386/ :) 22 фев. 092009-02-22 05:43:13

  0

Правда, этот комикс _is_ jrockway, но вы ошибаетесь. 22 фев. 092009-02-22 05:44:40

  0

Требуется много гордости (а не хорошего), чтобы предположить, что вы знаете больше о характере моего проекта, чем я. В этом случае удобство копирования одного файла вокруг - без требований CPAN - намного превосходит преимущества возможности разобрать CDATA и другие такие формы 22 фев. 092009-02-22 05:58:00

  0

... сложных HTML-документов, которые на самом деле никогда не будут попросил разобрать. 22 фев. 092009-02-22 05:58:44

  0

@raldi: Две вещи. Во-первых, риск здесь заключается в том, что, даже если вы создаете HTML самостоятельно, ваши требования могут измениться когда-нибудь. Использование заранее разработанного решения облегчает задачу заставить его работать перед лицом меняющихся требований. Конечно, только вы можете судить, разумно ли это здесь. 22 фев. 092009-02-22 15:21:07

  0

@raldi: Во-вторых, даже если это не лучшее решение для вас, это хорошо для этого решения, чтобы быть здесь, чтобы, если кто-то другой с подобной (но не такой же) проблемой найдет ваш вопрос здесь, ответ jrockway может работать когда один для ваших точных требований не будет. 22 фев. 092009-02-22 15:22:06

  0

Точно. Я объясняю, как это делать в целом. Если вам нужна конкретная помощь для ваших конкретных потребностей, применяется моя стандартная ставка для консультаций :) 22 фев. 092009-02-22 16:39:19

  0

@Adam: Если мои требования меняются когда-нибудь, и получается, что это была огромная ошибка, я могу отменить ее, удалив одну строку кода. Здесь не большая проблема. 24 фев. 092009-02-24 03:03:45


2

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

<.*?>(.*?)<.*?>|>(.*?)< 

Тогда вы можете работать на том, что по желанию.


0

Попробуйте один

(?=>)?(\w[^>]+?)(?=<)

это соответствует всем словам между тегами

  0

'(? =>)' Никогда не будет соответствовать, когда остальные будут совпадать. '(? <=>)' это то, что вы хотите. (Заменить '(? =>)?' С '(? <=>)' или '(? <=[>])') 19 окт. 122012-10-19 21:59:45


0

сдирать содержимое переменного размера даже из вложенных тегов вы можете использовать это регулярное выражение, которое на самом деле мини-регулярно грамматика для этого. (Примечание: PCRE машина)

(< =>?) ((?: \ W +) (?: \ S *)) *