Регулярное выражение соответствует словам или фразам в строке, но НЕ совпадает с частью URL или внутри тегов . (РНР)
Я знаю, что регулярное выражение не идеально подходит для использования со строками HTML, и я смотрел PHP Simple HTML DOM Parser, но все же считаю, что это путь. Все теги HTML будут сгенерированы моим программным обеспечением форума, чтобы они были согласованными и допустимыми HTML.
То, что я пытаюсь сделать, это сделать плагин, который найдет список ключевых слов (или фраз) в строке HTML и заменит их ссылкой, которую я указываю. Например, если кто-то набирает:
I use Amazon for that.
он заменит его на:
I use <a href="#" onclick="location.href='http://www.amazon.com'; return false;">Amazon</a> for that.
Проблема заключается, конечно, в том, что если "амазонка" находится в URL-адресе, она также будет заменена. Я решил эту проблему с функцией обратного вызова, найденной на этом сайте, слегка измененной.
Но теперь у меня все еще есть проблема, она все равно заменяет слова между тегами открытия и закрытия.
<a href="#" onclick="location.href='http://www.amazon.com'; return false;">My Amazon Link</a>
Он будет соответствовать "Amazon" в "My Amazon Link"
Мне действительно нужно, чтобы регулярное выражение соответствовало "амазонке" где угодно, кроме <a href
и </a>
Любые идеи?
Ответы
Ответ 1
Использование DOM, безусловно, было бы предпочтительнее.
Однако вы можете уйти от этого:
$result = preg_replace('%Amazon(?![^<]*</a>)%i', '<a href="http://www.amazon.com">Amazon</a>', $subject);
Он соответствует Amazon
, только если
- за ним не следует закрывающий тег
</a>
,
- он не является частью тега,
- нет промежуточных тегов, т.е. е. он будет сброшен, если теги могут быть вложены внутри тегов
<a>
.
Поэтому он изменит это:
I use Amazon for that.
I use <a href="http://www.amazon.com">Amazon</a> for that.
<a href="http://www.amazon.com">My Amazon Link</a>
It will match the "Amazon" in "My Amazon Link"
в это:
I use <a href="http://www.amazon.com">Amazon</a> for that.
I use <a href="http://www.amazon.com">Amazon</a> for that.
<a href="http://www.amazon.com">My Amazon Link</a>
It will match the "<a href="http://www.amazon.com">Amazon</a>" in "My <a href="http://www.amazon.com">Amazon</a> Link"
Ответ 2
Не делай этого. Вы не можете надежно сделать это с помощью Regex, независимо от того, насколько совместим ваш HTML.
Что-то вроде этого должно работать, однако:
<?php
$dom = new DOMDocument;
$dom->load('test.xml');
$x = new DOMXPath($dom);
$nodes = $x->query("//text()[contains(., 'Amazon')][not(ancestor::a)]");
foreach ($nodes as $node) {
while (false !== strpos($node->nodeValue, 'Amazon')) {
$word = $node->splitText(strpos($node->nodeValue, 'Amazon'));
$after = $word->splitText(6);
$link = $dom->createElement('a');
$link->setAttribute('href', 'http://www.amazon.com');
$word->parentNode->replaceChild($link, $word);
$link->appendChild($word);
$node = $after;
}
}
$html = $dom->saveHTML();
echo $html;
Это многословие, но оно действительно будет работать.
Ответ 3
Попробуйте здесь
Amazon(?![^<]*</a>)
Это приведет к поиску Amazon, и отрицательный lookahead гарантирует отсутствие закрывающего тега. И я ищу там только для не <
, так что я не буду читать открывающий тег случайно.
http://regexr.com
Ответ 4
К сожалению, я думаю, что логика, в которой вы нуждаетесь, еще сложнее, чем сопоставление текстового шаблона: -/
Я знаю, что это не тот ответ, который вы хотите услышать, но вы, вероятно, получите лучшие результаты с помощью модели DOM.
Здесь обсуждение этого вопроса в другом месте: http://coderzone.org/forum/index.php?topic=84.0
Можно ли просто запустить фильтр один раз, так что вы не закончите с обманами? Или исходный корпус также может содержать ссылки?
Ответ 5
Джо, воскресив этот вопрос, потому что у него было простое решение, о котором не упоминалось. (Нашел ваш вопрос, проведя некоторое исследование для общего вопроса о как исключить шаблоны в regex.)
При всех отказах в использовании regex для синтаксического анализа html, это простой способ сделать это.
Здесь наше простое регулярное выражение:
<a.*?</a>(*SKIP)(*F)|amazon
Левая часть чередования соответствует полному тегу <a... </a>
, а затем сознательно терпит неудачу. Правая сторона соответствует amazon
, и мы знаем, что это правильный amazon
, потому что это не соответствовало выражению слева.
В этой программе показано, как использовать регулярное выражение (см. результаты в нижней части онлайн-демонстрация):
<?php
$target = "word1 <a stuff amazon> </a> word2 amazon";
$regex = "~(?i)<a.*?</a>(*SKIP)(*F)|amazon~";
$repl= '<a href="http://www.amazon.com">Amazon</a>';
$new=preg_replace($regex,$repl,$target);
echo htmlentities($new);
Ссылка
Как сопоставить (или заменить) шаблон, за исключением ситуаций s1, s2, s3...
Ответ 6
Используйте этот код:
$p = '~((<a\s)(?(2)[^>]*?>))?(amazon)~smi';
$str = '<a href="http://www.amazon.com">Amazon</a>';
$s = preg_replace($p, "$1My $3 Link", $str);
var_dump($s);
OUTPUT
String(50) "<a href="http://www.amazon.com">My Amazon Link</a>"
Ответ 7
импровизация. Он должен связываться только в том случае, если это целое слово "Amazon", а не такие слова, как AmazonWorld.
$result = preg_replace('%\bAmazon(?![^<]*</a>)\b%i', '<a href="#" onclick="location.href='http://www.amazon.com'; return false;">Amazon</a>', $subject);