Как мне заставить мой preg_replace искать только слова, пока они НЕ находятся в теге ‹acronym›?

В PHP у меня есть строка $string и массив $acronyms (в форме «UK» => «United Kingdom»).

Теперь я хочу заменить все аббревиатуры в $string некоторыми HTML-тегами. Например, Hello UK должно превратиться в Hello <acronym title="United Kingdom">UK</acronym></pre>

Я делаю это так:

foreach($acronyms as $acronym => $tooltip){
     $string = preg_replace('/'.$acronym.'/i', ''.$acronym.'', $string);
}

Проблема в следующем: допустим, у меня есть текст Hello UK и есть массив для замены «Великобритания» на «Великобритания» и «Королевство» на «RandomWord». Затем текст заменится на Hello <acronym title="United <acronym title="RandomWord">Kingdom</acronym>">UK</acronym>, что, очевидно, является хаосом.

Итак, вопрос: Как заставить мой preg_replace искать только те слова, которые НЕ находятся внутри тега <acronym>? (ни в атрибуте title, ни в самом теге)

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

foreach($acronyms as $acronym => $tooltip){
        $acronyms[$acronym] = '<acronym title="'.$tooltip.'">'.$acronym.'</acronym>';
}
$string = str_ireplace(array_keys($acronyms), array_values($acronyms), $string);


person user2015253    schedule 27.01.2013    source источник
comment
Это точно так же, как: теги, кроме автономных тегов xhtml"> stackoverflow.com/questions/1732348/   -  person Muqito    schedule 27.01.2013
comment
Сначала удалите все аббревиатуры, а затем добавьте их снова.   -  person dualed    schedule 27.01.2013
comment
О, и обычно такие замены выполняются либо на клиенте (для Javascript), либо таким образом, что не меняется источник. Тогда ваша проблема просто не всплывает.   -  person dualed    schedule 27.01.2013


Ответы (3)


Вы можете использовать strtr(). Он не сканирует строку после выполнения замены:

foreach ($acronyms as $acronym => $tooltip) {
    $acronyms[$acronym] = sprintf('<acronym title="%s">%s</acronym>',
        htmlspecialchars($tooltip),
        htmlspecialchars($acronym)
    );
}

echo strtr($str, $acronyms);
person Ja͢ck    schedule 27.01.2013

Вот попытка версии регулярного выражения:

foreach($acronyms as $acronym => $tooltip){
    $rexp = '/' . $acronym . '(?!((?!<acronym).)*<\/acronym>)/i';
    $string = preg_replace($rexp, ''.$acronym.'', $string);
}

Кажется, работает для меня. Он делает следующее:

  1. Сопоставьте переменную $acronym с отрицательным взглядом вперед...
  2. где можно найти закрывающий тег аббревиатуры
  3. но остановите просмотр вперед, когда перед ним находится открывающий тег аббревиатуры.

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

Вот пример этого в действии: пример регулярного выражения gSkinner

person aaronjbaptiste    schedule 27.01.2013

Не пытайтесь делать все с помощью регулярных выражений:

  1. Проанализируйте свой HTML с помощью библиотеки синтаксического анализа HTML/XML.
  2. Переберите свои HTML-теги, замените то, что вам нужно заменить.
  3. Попросите свою «библиотеку синтаксического анализа html» преобразовать это обратно в «строку HTML».
person Julien Palard    schedule 27.01.2013