PHP Регулярное выражение для соответствия ключевому слову вне HTML-тега <a>

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

  1. Я хочу сопоставить keyword и <strong>keyword</strong>
  2. но <a href="someurl.html" target="_blank">keyword</a> и <a href="someur2.html">already linked keyword </a> НЕ должны быть сопоставлены

Меня интересует только сопоставление (и замена) keyword на первой строке.

Причина, по которой я хочу это, – заменить keyword <a href="dictionary.php?k=keyword">keyword</s> , но ТОЛЬКО, если keyword уже не находится в теге <a> .

Любая помощь будет высоко ценится!

 $str = preg_replace('~Moses(?!(?>[^<]*(?:<(?!/?a\b)[^<]*)*)</a>)~i', '<a href="novo-mega-link.php">$0</a>', $str); 

Выражение внутри негативного внешнего вида соответствует следующему закрывающему тегу </a> , но только если он не видит первый тег <a> . Если это удастся, это означает, что слово Moses находится внутри элемента привязки, поэтому просмотр не выполняется, и совпадение не происходит.

Вот демо .

Мне удалось сделать то, что я хотел ( без использования Regex ):

  • разбор каждого символа моей строки
  • удаление всех тегов <a> (копирование их во временный массив и сохранение заполнителя в строке)
  • str_replace новая строка, чтобы заменить все ключевые слова
  • повторное заполнение заполнителей оригинальными тегами <a>

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

 $str = <<<STRA Moses supposes his toeses are roses, but <a href="original-moses1.html">Moses</a> supposes erroneously; for nobody's toeses are posies of roses, as Moses supposes his toeses to be. Ganda <span class="cenas"><a href="original-moses2.html" target="_blank">Moses</a></span>! STRA; $arr1 = str_split($str); $arr_links = array(); $phrase_holder = ''; $current_a = 0; $goto_arr_links = false; $close_a = false; foreach($arr1 as $k => $v) { if ($close_a == true) { if ($v == '>') { $close_a = false; } continue; } if ($goto_arr_links == true) { $arr_links[$current_a] .= $v; } if ($v == '<' && $arr1[$k+1] == 'a') { /* <a */ // keep collecting every char until </a> $arr_links[$current_a] .= $v; $goto_arr_links = true; } elseif ($v == '<' && $arr1[$k+1] == '/' && $arr1[$k+2] == 'a' && $arr1[$k+3] == '>' ) { /* </a> */ $arr_links[$current_a] .= "/a>"; $goto_arr_links = false; $close_a = true; $phrase_holder .= "{%$current_a%}"; /* put a parameter holder on the phrase */ $current_a++; } elseif ($goto_arr_links == false) { $phrase_holder .= $v; } } echo "Links Array:\n"; print_r($arr_links); echo "\n\n\nPhrase Holder:\n"; echo $phrase_holder; echo "\n\n\n(pre) Final Phrase (with my keyword replaced):\n"; $final_phrase = str_replace("Moses", "<a href=\"novo-mega-link.php\">Moses</a>", $phrase_holder); echo $final_phrase; echo "\n\n\nFinal Phrase:\n"; foreach($arr_links as $k => $v) { $final_phrase = str_replace("{%$k%}", $v, $final_phrase); } echo $final_phrase; 

Выход:

Массив ссылок:

 Array ( [0] => <a href="original-moses1.html">Moses</a> [1] => <a href="original-moses2.html" target="_blank">Moses</a> ) 

Фразовый держатель:

 Moses supposes his toeses are roses, but {%0%} supposes erroneously; for nobody's toeses are posies of roses, as Moses supposes his toeses to be. Ganda <span class="cenas">{%1%}</span>! 

(pre) Окончательная фраза (с замененным ключевым словом):

 <a href="novo-mega-link.php">Moses</a> supposes his toeses are roses, but {%0%} supposes erroneously; for nobody's toeses are posies of roses, as <a href="novo-mega-link.php">Moses</a> supposes his toeses to be. Ganda <span class="cenas">{%1%}</span>! 

Финальная фраза:

 <a href="novo-mega-link.php">Moses</a> supposes his toeses are roses, but <a href="original-moses1.html">Moses</a> supposes erroneously; for nobody's toeses are posies of roses, as <a href="novo-mega-link.php">Moses</a> supposes his toeses to be. Ganda <span class="cenas"><a href="original-moses2.html" target="_blank">Moses</a></span>! 
 $lines = explode( "\n", $content ); $lines[0] = stri_replace( "keyword", "replacement", $lines[0] ); $content = implode( "\n", $lines ); 

или если вы явно хотите использовать регулярное выражение

 $lines = explode( "\n", $content ); $lines[0] = preg_replace( "/keyword/i", "replacement", $lines[0] ); $content = implode( "\n", $lines ); 

Подумайте об использовании библиотеки разбора HTML вместо обычного выражения, например simplehtmldom . Вы можете использовать его для обновления содержимого определенных тегов HTML (поэтому, игнорируя те, которые вы не хотите изменять). Тогда вам не придется использовать регулярное выражение; просто используйте функцию str_replace после фильтрации соответствующих тегов.