【问题标题】:Need to match ALL similar words/phrases using preg_match_all需要使用 preg_match_all 匹配所有相似的单词/短语
【发布时间】:2015-01-11 21:36:11
【问题描述】:

我正在尝试创建一个匹配字符串中所有相似单词/短语的模式。

例如,我需要匹配:“this”、“this is”、“this is it”、“that”、“that was”、“that was not”。

它只匹配“this”的第一次出现,但它应该匹配所有次出现。

我什至尝试了锚点和单词边界,但似乎没有任何效果。

我试过(简化):

$content = "this is it! that was not!";

preg_match_all('/(this|this is|this is it|that|that was|that was not)/i', $content, $results);

应该输出什么:

  • 这个
  • 这是
  • 就是这样
  • 那个
  • 那是
  • 那不是

【问题讨论】:

  • 使用/(this( is( it)?)?)/
  • 问题:如果您只想捕获您专门搜索的子字符串,为什么不满足于foreach 循环和substr_count
  • @Mr. Llama 你介意发布一个例子吗?
  • @Tom - 作为答案发布:stackoverflow.com/a/26933945/477563

标签: php regex web preg-match preg-match-all


【解决方案1】:

鉴于您只捕获要搜索的术语,最好使用foreach 循环和substr_count 来查看每个字符串出现的次数。

例如:

$haystack = "this is it! that was not! this is not a test!";
$needles = array(
    "this",
    "this is",
    "this is it",
    "that",
    "that was",
    "that was not");

foreach ($needles as $needle) {
    // substr_count is case sensitive, so make subject and search lowercase
    $hits = substr_count(strtolower($haystack), strtolower($needle));

    echo "Search '$needle' occurs $hits time(s)" . PHP_EOL;
}

上面会输出:

Search 'this' occurs 2 time(s)
Search 'this is' occurs 2 time(s)
Search 'this is it' occurs 1 time(s)
Search 'that' occurs 1 time(s)
Search 'that was' occurs 1 time(s)
Search 'that was not' occurs 1 time(s)

如果substr_count 不能提供您需要的灵活性,那么您可以随时将其替换为preg_match_all,并使用您的个人$needle 值作为搜索词。

【讨论】:

  • 感谢您发布示例。那么,如果我想将所有匹配项放入一个数组中,我该怎么做呢?抱歉,我不是最好的 PHP 程序员。
  • 匹配本身不会产生重大影响,因为您已经知道它们是什么(因为您实际上只是搜索它们)。但是,如果您想存储它们,可以在 echo 语句之后执行for ($i = 0; $i < $hits; $i++) { $matches[] = $needle; } 之类的操作。
  • 谢谢,这行得通。我将如何从数组中删除重复的匹配项?那么,如果“this is”匹配了两次,那么它只在数组中存储一次呢?
  • array_unique 函数会起作用吗?或者,有什么更好的吗?
  • @Tom - 只需删除 for 循环并使其变为 if ($hits > 0) { $matches[] = $needle; }
【解决方案2】:

怎么样:

$content = "this is it";
preg_match_all('/(?=(this))(?=(this is))(?=(this is it))/i', $content, $results);
print_r($results);

根据cmets编辑:

$content = "this is it";
preg_match_all('/(?=(this))(?=(this is))(?=(this is it))|(?=(that))(?=(that was))(?=(that was not))/i', $content, $results);
print_r($results);

输出:

Array
(
    [0] => Array
        (
            [0] => 
            [1] => 
        )

    [1] => Array
        (
            [0] => this
            [1] => 
        )

    [2] => Array
        (
            [0] => this is
            [1] => 
        )

    [3] => Array
        (
            [0] => this is it
            [1] => 
        )

    [4] => Array
        (
            [0] => 
            [1] => that
        )

    [5] => Array
        (
            [0] => 
            [1] => that was
        )

    [6] => Array
        (
            [0] => 
            [1] => that was not
        )

)

更通用:

$content = "this is it! that was not!";
preg_match_all('/\b(?=(\w+))(?=(\w+ \w+))(?=(\w+ \w+ \w+))\b/i', $content, $results);
print_r($results);

输出:

Array
(
    [0] => Array
        (
            [0] => 
            [1] => 
        )

    [1] => Array
        (
            [0] => this
            [1] => that
        )

    [2] => Array
        (
            [0] => this is
            [1] => that was
        )

    [3] => Array
        (
            [0] => this is it
            [1] => that was not
        )

)

【讨论】:

  • 谢谢,效果很好,但是有没有办法在不以“this”开头的模式中添加更多单词?例如,它还匹配不同的东西(除了上面的):“red”、“red apple”、“red apple tree”?
  • @Tom:对不起,我没听懂。您可能需要编辑您的问题并提供一些示例字符串和预期结果。
  • 不,它需要匹配那些确切的单词/短语。您的第一个示例效果很好,我只需要在模式中添加更多可能的匹配项。
  • 谢谢!效果很好!唯一的问题是,如果字符串仅包含部分单词/短语 - 它与它不匹配。例如,如果字符串仅包含“that was”,则它不匹配任何内容。有什么想法吗?
【解决方案3】:

问题是 shortest 字符串选项首先出现在您的或组中:

/(this|this is|this is it)/i

PHP 将检查测试字符串是否包含(this|this is|this is it) 从左到右的项目。一旦在测试字符串中找到匹配项,它将离开组。

这会起作用,因为 PHP 将首先搜索最长的字符串:

/(this is it|this is|this)/i

Demo

【讨论】:

  • 谢谢,这是有道理的,但它仍然没有显示数组中的所有可能结果。有什么想法吗?
  • 啊,我想我明白为什么它只在数组中显示“this is it”。我正在使用的测试字符串仅包含“this is it”,而您的测试字符串包含每个单词/短语。有没有办法只用“这就是它”来获得所有匹配项?
【解决方案4】:

您也可以改用以下正则表达式。

/(this(?:\sis(?:\sit)?)?)/i

【讨论】:

  • 但这根本不能回答问题。
猜你喜欢
  • 1970-01-01
  • 2011-02-28
  • 2021-05-11
  • 1970-01-01
  • 2012-03-23
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多