如何匹配不包含单词的字符串?

时间:2011-05-02 15:14:01

标签: php regex regex-negation

要匹配包含某些单词的字符串,我可以使用模式“/.*word.*/”。但是如何匹配一个不包含这个词的字符串?

示例:

我需要在一个大文本中找到一个子字符串,它由两个标签括起来,并且里面有一些像“Hello”这样的字符串。我想出的最好的:

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

但它也会匹配序列:

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

而且我不想匹配第一对div标签 - 因此我想要替换“。*?”比较“匹配任何字符串,除了不包含”。

测试用例

输入字符串:

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

我需要抓住

<div>Hello!</div>

3 个答案:

答案 0 :(得分:4)

问题的更好标题可能是:“匹配包含特定子字符串的DIV元素。”首先必须说正则表达式不是最好的工具工作。使用HTML解析器解析标记会更好,然后在每个DIV元素的内容中搜索所需的子字符串。也就是说,因为你不想更多地了解如何使用正则表达式来匹配其他东西,所以下面描述了使用正则表达式进行此操作的有限方法。

正如Dogbert正确指出的那样,这个问题确实与Regular expression to match string not containing a word?重复。但是,我看到你已经查看了这个问题,但需要知道如何将这种技术应用于子模式。

要匹配不包含特定单词(或单词)的字符串(子模式)的一部分,您需要在每个字符之前应用否定先行断言检查。以下是打开和关闭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>

它也会在嵌套的DIV元素的最里面找到“HELLO”:

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

但是,如前所述,它将 NOT 找到位于非最内层嵌套DIV元素中的“HELLO”字符串,如下所示:

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

要做到这一点,这是一个更复杂的解决方案。

很多情况下此解决方案可能会失败。再来一次。我建议使用HTML解析器。

答案 1 :(得分:3)

'~<div>(?!.*?Bye\..*?</div>).+?</div>~'

答案 2 :(得分:0)

你能不能检查一下你是否没有得到匹配?

如果您正在寻找除“单词”之外的任何内容:

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

仅当“word” 找不到

时,才会在if下方运行代码。