Xpoint
   [напомнить пароль]

Как заменить слова только вне параметров тегов?

Метки: [без меток]
2010-11-24 02:53:25 [обр] Легеров Алексей[досье]

Есть HTML-код - форматированный текст, где требуемое "слово" может встречаться и в тегах в качестве значений title, alt или прочих параметров. К сожалению, этот код - лишь форматирование, т.е. текст может начинаться как с открывающих тегов, так и без них.
Есть ли простое решение (вроде ~s///), которое позволит однократно заменить "слово" только вне параметров тегов?
Пытался использовать код:

$text=~s/^(.*?:(?(<)[^>]*>)[^<>]*) слово/$1 другое слово/i;

Скорее всего не разобрался в последовательностях. Правильно ли читаю: (.*?:(?(<)[^>]*>)[^<>]*) - "любые символы, после них если открывающая угловая скобка, то за ней что-то кроме закрывающей и обязательно закрывающая, затем любые символы кроме угловых скобок"? Или конструкция (?(...)...) неправильно понята?

спустя 12 минут [обр] Легеров Алексей[досье]
Простите ?: - лишние в коде. Ошибся пытаясь запретить захват, но сути не меняет, без этого тоже не работает.
спустя 31 минуту [обр] Легеров Алексей[досье]

Поспешил спросить, нашёл решение:

$text=~s/^((?:[^<>]*<[^>]+>[^<>]*)*[^<]*) слово/$1 другое слово/i;

Тем не менее, можно ли здесь же использовать конструкцию (?(...)...) Хотелось бы разобрать в том как она работает.

спустя 1 час 12 минут [обр] Легеров Алексей[досье]
Рано обрадовался. Найденное решение дает супернагрузку - на два порядка больше процессорного времени ест по сравнению с заменой без внимания к угловым скобкам. Есть ли другое решение?
спустя 8 минут [обр] Ali(0/10)[досье]

Вы пытались в конструкцию (?(...)...) скормить литерал в условие, а в условии не могут быть литералы.
Могут быть ссылки, именованные группы, код, еще какая-то фигня.

Иначе говоря, (?(<)xxx) не означает «если открывающая угловая скобка, то за ней что-то». Это вообще должна быть ошибка разбора регэкспа.

Тут можно попробовать что-то вроде (<)?(?(1)xxx), то есть «если совпало первая группа и она не пустая, то ...»

спустя 24 минуты [обр] Ali(0/10)[досье]

А вообще вы зря к такой задаче с регэкспами подходите… HTML вещь страшная, многие выражения ломаются на вещах типа <img src="next.gif" alt=">>>">,
а в жизни такое встречается :) Лучше взять лояльный парсер, отделить элементы от текста, и там уже заменять.

Хотя для наколенного поделия я бы вполне обошелся таким, например, регэкспом:

$a =~ s/(([^<]*?|(<[^>]+>))+)слово/$1другое слово/ig;

спустя 4 часа 42 минуты [обр] zloyrusskiy(0/3)[досье]

Парсить HTML регулярками крайне ненадёжно, почему бы не попробовать Mojo::DOM и запросом вида

$dom->find(q#img#)->each(sub {
  my $el = shift;
  $el->attrs->{alt} = 'другое слово' if $el->attrs->{alt} eq "слово"
});

всё сделать правильно.

спустя 1 час 9 минут [обр] Евгений Седов aka KPbIC(0/187)[досье]
спустя 4 часа 28 минут [обр] Легеров Алексей[досье]

Начну сначала. Настоящая суть задачи - формирование базы устойчивых частей слов/фраз (тегов) с соответствующими URL, а в публикаторе сайта основные тексты прогонять через программу заменяющую слова/фразы, содержащие эти устойчивые части из базы, на ссылки на указанный URL.
Почему искал простой вариант: База ссылок уже большая. Текстов на каждой странице (текстовых блоков) несколько. Получается задача прогнать каждый текст по всему массиву тегов, для каждого проводя сравнение и замену. Нагрузка на процессор в любом случае будет значительной. Ищу относительно несложного решения (почему ищу в ~s///) и оптимального по нагрузке.
К чему пришел: для упрощения проверки обязал все тексты начинаться с открывающего тега HTML и все тексты прогоняю через

$text=~s/(>[^<]+)слово/$1<a href=URL>слово<\/a>/i;

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

спустя 3 минуты [обр] Легеров Алексей[досье]
+ вместо * в коде использовал сознательно - лучше если ссылка будет вставлена внутри абзаца/ячейки, чем вначале, даже если есть риск ее не поставить вообще.
Powered by POEM™ Engine Copyright © 2002-2005