Автоматически конвертировать ключевые слова в ссылки в php

Я пытаюсь преобразовать определенные ключевые слова в текст, который хранится в массиве, к ссылкам.

Пример текста:

$text='This text contains many keywords, but also formated <a href="#keywords" title="keywords">keywords</a>.' 

Поэтому теперь я хочу преобразовать ключевые слова в <a href="#keywords" title="keywords">#keywords</a> .

Я использовал очень простую функцию preg_replace

 preg_replace('/keywords/i',' <a href="#keywords">keywords</a> ',$text); 

но, очевидно, он преобразует в ссылку также строку, уже отформатированную как ссылку, поэтому я получаю беспорядочный html как:

 $text='This text contains many <a href="#keywords" title="keywords">keywords</a>, but also formated <a href="#<a href="#keywords" title="keywords">keywords</a>" title="<a href="#keywords" title="keywords">keywords</a>"><a href="#keywords" title="keywords">keywords</a></a>.' 

Ожидаемый результат:

 $text='This text contains many <a href="#keywords" title="keywords">keywords</a>, but also formated <a href="#keywords" title="keywords">keywords</a>.' 

Какие-либо предложения? СПАСИБО

РЕДАКТИРОВАТЬ

Мы находимся на одном шагу от идеальной функции, но в этом случае все еще не работает:

 $text='This text contains many keywords, but also formated <a href="http://www.keywords.com/keywords" title="keywords">keywords</a>.' 

В этом случае он заменяет также слова keywords в href, поэтому мы снова получаем грязный код, например

  <a href="http://www.<a href="http://www.keywords.com/keywords" title="keywords">keywords</a>.com/<a href="http://www.keywords.com/keywords" title="keywords">keywords</a>" title="keywords">keywords</a> 

Related of "Автоматически конвертировать ключевые слова в ссылки в php"

Я не очень хорош с регулярными выражениями, но, возможно, это будет работать:

 /[^#>"]keywords/i 

Я думаю, что это будет сделано, это игнорировать любые примеры >keywords , "keywords и "keywords и находить остальное.


EDIT :

После тестирования это выглядит так же, как и место перед словом, и не работает, если keywords являются началом строки. Он также не сохранил первоначальную капитализацию. Я тестировал этот, и он отлично работает для меня:

 $string = "Keywords and keywords, plus some more keywords with the original <a href=\"#keywords\" title=\"keywords\">keywords</a>."; $string = preg_replace("/(?<![#>\"])keywords/i", "<a href=\"#keywords\">$0</a>", $string); echo $string; 

Первые три заменяются, сохраняя первоначальную заглавную букву, а последняя остается нетронутой. В этом случае используется отрицательный lookbehind и backreferences .


EDIT 2:

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

 $string = 'This text contains many keywords, but also formated <a href="http://www.keywords.com/keywords" title="keywords">keywords</a>.'; $string = preg_replace("/(?<![#>\".\/])keywords/i", "<a href=\"http://www.keywords.com/keywords\" title=\"keywords\">$0</a>", $string); echo $string; // outputs: This text contains many <a href="http://www.keywords.com/keywords" title="keywords">keywords</a>, but also formated <a href="http://www.keywords.com/keywords" title="keywords">keywords</a>. 

Это заменит все экземпляры keywords которым не предшествуют # , > , " , . Или or.

Вот проблема:

Ключевое слово может быть внутри href, заголовка или текста ссылки и где угодно (например, если ключевое слово было sanity и у вас уже было href="insanity" . Или еще хуже, у вас может быть не ключевое слово ссылка, которая содержит ключевое слово, что-то вроде:

 <a href="http://example.org/">Click here to find more keywords and such!</a> 

В приведенном выше примере, хотя он подходит для любых других возможных критериев (у него есть пробелы до и после того, как они были самыми легкими для тестирования), это все равно приведет к ссылке в пределах ссылки, которая, как я думаю, нарушает Интернет.

Из-за этого вам нужно использовать lookbehinds и lookbehinds чтобы проверить, lookbehinds ли ключевое слово в ссылку. Но есть один улов: lookbehind должны иметь определенный шаблон (что означает отсутствие диких карт).

Я думал, что буду героем и покажу вам легкое решение вашей проблемы, что было бы чем-то вроде:

 '/(?<!\<a.?>)[list|of|keywords](?!\<\/a>)/' 

Кроме того, вы не можете этого сделать, потому что lookbehind в этом случае имеет этот подстановочный знак. Без этого вы получите сверхъестественное выражение.

Поэтому моя предложенная альтернатива заключается в том, чтобы использовать регулярное выражение для поиска всех элементов ссылки, затем str_replace чтобы заменить их на placeholder, а затем заменив их заполнителем в конце.

Вот как я это сделал:

 $text='This text contains many keywords, but also formated <a href="#keywords" title="keywords">keywords</a>.'; $keywords = array('text', 'formatted', 'keywords'); //This is just to make the regex easier $keyword_list_pattern = '['. implode($keywords,"|") .']'; // First, get all matching keywords that are inside link elements preg_match_all('/<a.*' . $keyword_list_pattern . '.*<\/a>/', $text, $links); $links = array_unique($links[0]); // Cleaning up array for next step. // Second, swap out all matches with a placeholder, and build restore array: foreach($links as $count => $link) { $link_key = "xxx_{$count}_xxx"; $restore_links[$link_key] = $link; $text = str_replace($link, $link_key, $text); } // Third, we build a nice replacement array for the keywords: foreach($keywords as $keyword) { $keyword_links[$keyword] = "<a href='#$keyword'>$keyword</a>"; } // Merge the restore links to the bottom of the keyword links for one mass replacement: $keyword_links = array_merge($keyword_links, $restore_links); $text = str_replace(array_keys($keyword_links), $keyword_links, $text); echo $text; 

Вы можете изменить свой RegEx так, чтобы он ориентировался только на ключевые слова с пространством впереди. Поскольку форматированные ключевые слова не содержат пробела. Вот пример.

 $text = preg_replace('/ keywords/i',' <a href="#keywords">keywords</a>',$text);