Как сопоставить строку, которая не содержит слова? - PullRequest
4 голосов
/ 02 мая 2011

Чтобы соответствовать строке, которая содержит какое-то слово, я могу использовать шаблон "/.*word.*/".Но как мне сопоставить строку, которая не содержит это слово?

Пример:

Мне нужно найти подстроку в большом тексте, который заключен в два тега, и, ивнутри есть строка типа «Hello».Лучшее, что я придумал:

"@<div>(.*?Hello.?*)</div>@i"

Но это также будет соответствовать последовательности:

<div>Bye.</div><div>Hello!</div>

И я не хочу совпадать с первой парой тегов div - поэтому я хочузаменить ".*?"с чем-то вроде «соответствует любой строке, кроме той, которая не содержит».

Контрольный пример :

Для входной строки:

<div>Bye.</div><div>Hello!</div>

Iнадо ловить

<div>Hello!</div>

Ответы [ 3 ]

4 голосов
/ 02 мая 2011

Лучшим заголовком для вопроса может быть: "Соответствует элементу DIV, содержащему определенную подстроку." Сначала нужно сказать, что регулярное выражение - не лучший инструмент для этой работы. Было бы намного лучше использовать анализатор HTML для анализа разметки, а затем искать содержимое каждого элемента DIV для поиска нужной подстроки. Тем не менее, поскольку вы не хотите больше знать о том, как использовать регулярные выражения для сопоставления с вещами, которые не являются чем-то другим, следующее описывает ограниченный способ сделать это с помощью регулярных выражений.

Как правильно указывает Догберт, этот вопрос действительно является дубликатом Регулярного выражения для соответствия строке, не содержащей слова? . Тем не менее, я вижу, что вы рассмотрели этот вопрос, но вам необходимо знать, как применить эту технику к подшаблону.

Чтобы сопоставить часть строки (подшаблон), которая не включает в себя определенное слово (или слова), вам необходимо применить проверку на отрицательное предпросмотр перед каждым и каждым символом. Вот как это делается для текста между открывающими и закрывающими тегами DIV. Обратите внимание, что при использовании только одного регулярного выражения, поскольку элементы DIV могут быть вложенными, разумно найти "HELLO" в «самом внутреннем» из вложенных элементов DIV.

Псевдокод:

  • Соответствует открывающему тегу DIV.
  • Ленивое совпадение с нулем или более символов, каждый из которых не является началом <div или </div.
  • Как только искомая строка: "HELLO" найдена, продолжайте и сопоставьте ее.
  • Продолжить (жадно) сопоставляя ноль или более символов, каждый из которых не является началом <div или </div.
  • Соответствует закрывающему тегу </div>.

Обратите внимание, что для сопоставления только с "самым внутренним" содержимым DIV необходимо исключить <DIV и </DIV при сканировании содержимого элемента по одному символу за раз. Вот соответствующее регулярное выражение в виде проверенной функции PHP:

// Find an innermost DIV element containing the string "HELLO".
function p1($text) {
    $re = '% # Match innermost DIV element containing "HELLO"
        <div[^>]*>        # DIV element start tag.
        (?:               # Group to match contents up to "HELLO".
          (?!</?div\b)    # Assert this char is not start of DIV tag.
          .               # Safe to match this non-DIV-tag char.
        )*?               # Lazily match contents one chara at a time.
        \bhello\b         # Match target "HELLO" word inside DIV.
        (?:               # Group to match content following "HELLO".
          (?!</?div\b)    # Assert this char is not start of DIV tag.
          .               # Safe to match this non-DIV-tag char.
        )*                # Greedily match contents one chara at a time.
        </div>            # DIV element end tag.
        %six';
    if (preg_match($re, $text, $matches)) {
        // Match found.
        return $matches[0];
    } else {
        // No match found
        return 'no-match';
    }
}

Эта функция будет правильно соответствовать желаемому элементу DIV ваших следующих тестовых данных:

<div>Bye.</div><div>Hello!</div>

Он также будет правильно находить "HELLO" внутри самых вложенных элементов DIV:

<div>
    <div>
        Hello world!
    </div>
</div>

Но, как указывалось ранее, NOT найдет строку "HELLO", расположенную внутри не внутренних вложенных элементов DIV, так:

<div>
    Hello,
    <div>
        world!
    </div>
</div>

Это гораздо более сложное решение.

Есть много случаев, когда это решение может дать сбой. Снова. Я рекомендую использовать анализатор HTML.

3 голосов
/ 02 мая 2011
'~<div>(?!.*?Bye\..*?</div>).+?</div>~'
0 голосов
/ 02 мая 2011

Разве вы не можете просто проверить, не получили ли вы совпадение?

Если вы ищете что-нибудь, кроме слова «слово»:

if(!preg_match("/word/i", $myString))

Это будетзапускайте код под if, только если «слово» было , а не найдено.

...