2012-04-01 2 views
0

Я пишу глоссарий - он должен найти известные слова в тексте и заменить его ссылкой. Он не должен заменять слово, если это ссылка ancor (<a href="...">word</a>) или атрибут (<span class="word">...</span>).Regex for glossary replace

Я написал код:

$x = '<div>DVB-S2. DVB-S. DVB-S2DVB-S <sss DVB-S2 /> DVB-S2 <a href="dd">DVB-S2</a> DVB-S2 Hot bird 6/Hot Bird 8/Hot bird 9, 13.0</div>'; 

$word = 'Hot Bird 8'; 
$x = preg_replace("'(?<=[\s\>])(" . $word . ")(?=[^\d\w\-])(?!([^<]+)?>)'is", "<a href=\"s2\">$1</a>", $x); 

$word = 'DVB-S2'; 
$x = preg_replace("'(?<=[\s\>])(" . $word . ")(?=[^\d\w\-])(?!([^<]+)?>)'is", "<a href=\"s2\">$1</a>", $x); 

echo $x; 

Но заменить <a href="dd">DVB-S2</a> на <a href="dd"><a href="s2">DVB-S2</a></a>.

Как это исправить?

+0

ив тестирование кода и Ive заметил, что первый preg_replace ничего не делает – abugnais

+0

Более важным является второй регулярное выражение и проблемы с заменой якоря. – gvozd1989

+0

Вы хотите заменить исходный тег, если он существует? – abugnais

ответ

0

это то, что я получил, я надеюсь, что он работает

echo preg_replace("@((?!<a\s*[^<>]*>.*?))($word)((?!</a>.))@i",'$1<a href="">$2</a>$3',$html) . chr(10); 

, которые будут выводить

<div><a href="">DVB-S2</a>. DVB-S. <a href="">DVB-S2</a>DVB-S <sss <a href="">DVB-S2</a> /> <a href="">DVB-S2</a> <a href="dd">DVB-S2</a> <a href="">DVB-S2</a> Hot bird 6/Hot Bird 8/Hot bird 9, 13.0</div> 
+0

Спасибо очень много - это работает, я редактировал его исправить:. 'DVB-S2 />' To: '@ ((. ?? ] *>. *?)) ($ Word) ((? = [^ <> \ S]) (?!.)) @ I' – gvozd1989

0

Вы должны разбить это на три правила:

  1. Слово ограничена с обеих сторон характера без слов или BO [SL]/EO [SL].
  2. Слово не между < и его соответствием>.
  3. Слово не между и.

Нам нужен положительный предпросмотр и для просмотра назад правил (1):

(?<=^|\W)word(?=\W|$) 

\W захватывает символы без слов, так что ничего, кроме букв, цифр и символов подчеркивания. Это не совсем то же самое, что и ваша версия, но вы можете настроить по мере необходимости. \b также может быть хорошим выбором, и в этом случае вам не понадобится знак каретки и доллара.

Теперь добавьте отрицательный для просмотра назад правил (2):

(?<!<[^>]*)(?<=^|\W)(DVB-S2)(?=\W|$) 

Это предотвращает совпадение, когда слово предшествуют < и любые не- > символов, то есть, когда он находится в середине любого тега HTML.

Теперь добавьте отрицательный предпросмотр для правила (3):

(?<!<[^>]*)(?<=^|\W)(DVB-S2)(?=\W|$)(?!</a>) 

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

Все вышеперечисленное написано в регулярном выражении .NET-dialect, я предполагаю, что PHP достаточно схож, чтобы это работало для вас.

+0

Thx, но это не сработает: компиляция не выполнена: утверждение lookbehind не фиксировано длины при смещении 10 – gvozd1989

+0

Bummer, работает в .NET. :( – richardtallent

+0

Спасибо в любом случае - ваш ответ очень полезно для понимания техники – gvozd1989