Захват всех вхождений определенного слова, когда он не является частью ссылки

avatar
Davide Casiraghi
6 февраля 2021 в 10:33
202
5
3

Я пытаюсь получить с помощью регулярного выражения с использованием диалекта PCRE2 из текста HTML все вхождения слова «яблоко». Но за исключением слова «яблоко», это часть ссылки.
Я новичок в Regex, наверное, делаю довольно простую ошибку.

\bapple\b

Итак, следующий текст должен соответствовать первому вхождению, но не второму и третьему.

Lorem ipsum apple sit amet, consectetur <a href="#">apple</a> elit <a href="/test/apple">lorem</a>. 

Что я делаю не так?

Источник
mayo
8 октября 2015 в 17:17
0

Вы хотите сопоставить всю 4-ю строчку? или просто «Match Me»?

Lizardx
8 октября 2015 в 19:34
0

Ограничен ли набор тегов, которые будут обертывать «Foo Bar»? Это просто <span> .... </span> или могут быть другие теги, например <em> <strong> <b> и т. Д.? Должен ли он учитывать недействительный или небрежный html, например: <span> foo bar </div> или такие вещи, как <h2> foo bar </h2>?

danbrellis
8 октября 2015 в 22:01
0

только что видел ваш комментарий, просто Match Me в 4-й строке - см. мой отредактированный вопрос.

danbrellis
8 октября 2015 в 22:04
0

lizardx - могут быть другие теги, все, что будет допустимым внутри тега <a>. Теоретически неряшливого html не будет.

Ответы (5)

avatar
anubhava
6 февраля 2021 в 10:46
5

В PCRE вы можете использовать это регулярное выражение:

~(?is)<a .*?</a>(*SKIP)(*F)|\bapple\b~

Демонстрация RegEx

Детали RegEx:

  • (?is): включить режим игнорирования регистра и DOTALL
  • <a .*?</a>: сопоставьте текст от <a до </a>, чтобы пропустить все <a> теги
  • (*SKIP)(*F): вместе обеспечивают хорошую альтернативу ограничения, заключающуюся в том, что в регулярном выражении PCRE нельзя использовать ретроспективный поиск переменной длины
  • |: ИЛИ
  • \bapple\b: слово соответствия apple
Davide Casiraghi
6 февраля 2021 в 10:51
1

Удивительный! Спасибо!! Мне бы потребовались годы, чтобы понять это без вашей помощи!

avatar
Wiktor Stribiżew
6 февраля 2021 в 13:24
0

Поскольку регулярное выражение PHP основано на PCRE2, вы можете использовать (*SKIP)(*F) / (*SKIP)(*FAIL) регулярное выражение:

/<a(?:\s[^>]*)?>.*?<\/a>(*SKIP)(*F)|\bMatch Me\b/is

См. демонстрацию регулярных выражений.

Подробности

  • <a - <a или <A (поскольку используется флаг i, шаблон не чувствителен к регистру)
  • (?:\s[^>]*)? - необязательное вхождение пробельного символа (\s), а затем любой ноль или более символов, кроме > (см. [^>]*) (эта часть обеспечивает соответствие <a>, а также <a attr=value attr2=value2...> виды тегов)
  • > - a > символ
  • .*? - любой ноль или более символов, как можно меньше (флаг s позволяет . соответствовать символам разрыва строки)
  • <\/a> - </a> или </A>
  • (*SKIP)(*F) - пропустить совпадение и продолжить поиск совпадений с позиции, где произошла ошибка
  • | - или
  • \bMatch Me\b - целое слово Match me (не заключенное в буквы, цифры или _ символы).
avatar
Tomeh
2 мая 2017 в 10:13
2

Сопоставление HTML с регулярным выражением довольно сложно. В принятом здесь ответе не допускаются строки, в которых совпадают два отдельных тега привязки, например:

HTML:

<a href="#">Don't Match Me <span>web</span></a>
match me
<a href="#">Don't Match Me</a>match me<a href="#">Don't Match Me</a>

Раньше я использовал для этого следующее регулярное выражение, но это будет работать только в php: https://regex101.com/r/v0FfFC/1

<a[^>]*>(?:[a-zA-Z0-9\s'\-\. ]|(?:<(.*)>.*<\/\1>))*<\/a>(*SKIP)(*FAIL)|\b(match me)\b(?=[^>]*(?:<|$))
danbrellis
2 мая 2017 в 13:43
1

Спасибо, что взглянули на это еще раз. Вы были правы, встав между двумя якорями. Для процветания регулярное выражение /<a[^>]*>(?:[a-zA-Z0-9\s'\-\. ]|(?:<(.*)>.*<\/\1>))*<\/a>(*SKIP)(*FAIL)|\b(match me)\b(?=[^>]*(?:<|$))/gi

Tomeh
2 мая 2017 в 23:10
0

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

avatar
user993553
9 октября 2015 в 18:15
1

Комментарий обновления до ответа:

match me(?!.*?\<\/a\>) 

https://regex101.com/r/hH3rL1/1

geoidesic
5 января 2017 в 17:20
0

Это принятый ответ, но он, похоже, не работает в моем движке регулярных выражений (Sublime Text 2) ... он соответствует всем строкам.

Tomeh
2 мая 2017 в 09:04
0

Однако это не работает, если желаемое совпадение находится между двумя якорными тегами, то есть <a href="#">Don't Match Me</a> match me <a href="#">Don't Match Me</a>

avatar
mayo
8 октября 2015 в 19:24
0

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

/^(?!.*(\<a.*?\>)).*$/ism

https://regex101.com/r/kE4mJ0/1

danbrellis
8 октября 2015 в 22:00
0

mayo- большое спасибо, что взглянули на это. Думаю, я не был кристально чистым. Это не обязательно в отдельных строках, это может быть одно и то же: <a href="#"> Don't Match Me <span> web </span> </a> <a href="#"> Не подбирай меня </a> Подбирай меня <span> Подбирай меня </span>. И мне нужно иметь возможность сопоставить конкретный текст «Match Me» ... если только он не находится внутри тега привязки.

user993553
9 октября 2015 в 03:51
1

сопоставьте мне (?!. *? \ <\ / a \>) это работает для вашей проблемы?

danbrellis
9 октября 2015 в 13:58
0

да, думаю, все! Не возражаете добавить это в качестве ответа?

mayo
9 октября 2015 в 16:44
0

Похоже, решение @ user993553 - это то, что вы ищете!