Как мне сопоставить текст в HTML, который не находится внутри тегов? - PullRequest
8 голосов
/ 22 февраля 2009

С учетом такой строки:

<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-адреса в теге тега.

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

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

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

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

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

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

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

Ответы [ 5 ]

10 голосов
/ 22 февраля 2009

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

s%(>|\G)([^<]*?)($key)%$1$2<b>$3</b>%g
7 голосов
/ 22 февраля 2009

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

#!/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.)

2 голосов
/ 22 февраля 2009

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

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

Затем вы можете работать с этим по своему усмотрению.

0 голосов
/ 27 мая 2014

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

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

0 голосов
/ 20 июня 2012

Попробуйте это

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

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

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...