PHP Regex сопоставляет слова в строке, исключая одно конкретное слово - PullRequest
5 голосов
/ 22 сентября 2011

У меня есть текст ($ txt), массив слов ($ words). Я хочу добавить ссылку и слово ($ wordToExclude), которое не должно быть заменено.

$words = array ('adipiscing','molestie','fringilla');
$wordToExclude = 'consectetur adipiscing';


$txt = 'Lorem ipsum dolor sit amet, consectetur adipiscing elit. Quisque
mattis tincidunt dolor sed consequat. Sed rutrum, mauris convallis bibendum 
dignissim, ligula sem molestie massa, vitae condimentum neque sem non tellus.
Aenean dolor enim, cursus vel sodales ac, condimentum ac erat. Quisque
lobortis libero nec arcu fringilla imperdiet. Pellentesque commodo, 
arcu et dictum tincidunt, ipsum elit molestie ipsum, ut ultricies nisl
neque in velit. Curabitur luctus dui id urna consequat vitae mattis
turpis pretium. Donec nec adipiscing velit.'

Я хочучтобы получить этот результат:

$txt = 'Lorem ipsum dolor sit amet, consectetur adipiscing elit. Quisque
mattis tincidunt dolor sed consequat. Sed rutrum, mauris convallis bibendum 
dignissim, ligula sem <a href="#">molestie</a> massa, vitae condimentum neque sem non tellus.
Aenean dolor enim, cursus vel sodales ac, condimentum ac erat. Quisque
lobortis libero nec arcu <a href="#">fringilla</a> imperdiet. Pellentesque commodo, 
arcu et dictum tincidunt, ipsum elit <a href="#">molestie</a> ipsum, ut ultricies nisl
neque in velit. Curabitur luctus dui id urna consequat vitae mattis
turpis pretium. Donec nec <a href="#">adipiscing</a> velit.'

Ответы [ 3 ]

3 голосов
/ 22 сентября 2011
$result = preg_replace(
    '/\b                 # Word boundary
    (                    # Match one of the following:
     (?<!consectetur\s)  #  (unless preceded by "consectetur "
     adipiscing          #  adipiscing
    |                    # or
     molestie            #  molestie
    |                    # etc.
     fringilla
    )                    # End of alternation
    \b                   # Word boundary
    /ix', 
    '<a href="#">\1</a>', $subject);
2 голосов
/ 22 сентября 2011

Хорошо, док!Хотя я думаю, что это технически выполнимо, решения, которые я предложил, на данный момент довольно мягкие:

s%(?!consectetur adipiscing)(adipiscing|molestie|fringilla)(?<!consectetur adipiscing)%<a href="#LinkBasedUpon$1">$1</a>%s

повороты ...

sit amet, consecteturadipiscing элит.Quisque ... ligula sem molestie massa ... nec arcu fringilla imperdiet ... nec adipiscing Velit.

в...

Сиди, Амет, Заклинатель, Адептирующий, Элит.Quisque ... ligula sem <a href="#LinkBasedUponmolestie"> molestie </a> massa ... nec arcu <a href="#LinkBasedUponfringilla"> fringilla </a> imperdiet ... nec <a href="#LinkBasedUponadipiscing"> adipiscing</a> velit.

Причина, по которой это мягкое решение заключается в том, что он не обрабатывает частичные слова или другие случаи, когда исключаемые слова не начинаются или заканчиваютсяодно из слов для сопоставления.Например, если бы мы добавили исключенное слово (то есть consectetur adipiscing elit), это выражение в конечном итоге соответствовало бы adipiscing в consectetur adipiscing elit, потому что adipiscing не начинается и не заканчивается так же, как consectetur adipiscing elit

Это должно работать до тех пор, пока исключаемое вами «слово» (A B C) всегда заканчивается или начинается с одного из найденных слов (C|X|E содержит C в нем и A B Cзаканчивается словом C, поэтому должно работать ...)

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

Причина, по которой слова «не совпадают» должны начинаться или заканчиваться однимиз совпавших слов заключается в том, что в этом решении используется отрицательный прогноз перед совпадением и отрицательный просмотр после совпадения, чтобы убедиться, что сопоставленная последовательность не соответствует словам, которые не должны быть сопоставлены (имеет ли это смысл?)

}

Существуют определенные решения для этого, но они требуют значительных усилий как процессора, так и процессора, и экспоненциально увеличиваются в зависимости от размера списков слов и длиныискомый текст и спецификацииС требованиями - и вы никогда ничего не указали, так что я не буду вдаваться в подробности.Дайте мне знать, если это достаточно хорошо для вашей ситуации!

0 голосов
/ 22 сентября 2011

Я вижу, вы делаете это на PHP. Я понимаю, что у вас есть Массив слов для поиска в тексте, и вам нужно заменить их ссылками. Также у вас есть ОДНА строка, которую нужно исключить при выполнении замены. Возможно, вместо того, чтобы писать классные и чистые, но сложные регулярные выражения, как насчет этого практического, хотя, вероятно, не самого хорошего решения:

Вы разбили задачу на подзадачи:

  1. используйте preg_match_all, чтобы найти смещения всех вхождений исключенной строки (вы знаете длину строки (strlen), а с флагом PREG_OFFSET_CAPTURE для preg_match_all вы определите точные начало и конец - если их больше чем один)
  2. сделать foreach в вашем списке слов и снова использовать preg_match_all, чтобы получить все вхождения слов, которые необходимо заменить ссылками
  3. сравните позиции, найденные на шаге 2, с позициями, найденными на шаге 1, и, если они находятся снаружи, сделайте замену или пропустите, если вы получите перекрытие

Конечно, он не будет однострочным, но его будет легко кодировать, а потом, вероятно, будет легко читать и позже.

...