在找到不同的特定单词后,计算特定单词的出现次数



我对正则表达式相当陌生,并且被困在下面,我尝试使用preg_match_all来计算世界之后的hello数量。

如果我使用"world".+(hello),它计入最后一个问候;"world".*?(hello)在第一个问候中停止,都给出了一个计数。

blah blah blah
hello
blah blah blah
class="world" 
blah blah blah
hello 
blah blah
hello
blah blah blah
hello
blah blah blah

我期待3作为计数,因为world之前的hello不应该被计算在内。

使用简单正则表达式的另一个选项:

if(preg_match('/"world".*/s', $str, $out)) {
echo preg_match_all('/bhellob/', $out[0]);
}

在tio.run上观看演示

您可以在此处使用单个preg_match_all调用:

$text = "blah blah blahnhellonblah blah blahnclass="world" nblah blah blahnhello nblah blahnhellonblah blah blahnhellonblah blah blah";
echo preg_match_all('~(?:G(?!^)|bworldb).*?Kbhellob~s', $text);

请参阅正则表达式演示和 PHP 演示。详情

  • (?:G(?!^)|bworldb)- 前一场比赛的结束(G(?!^)执行此检查:G匹配字符串的开头或前一匹配位置的结束,因此我们需要排除字符串位置的开始,这是通过(?!^)负前瞻完成的)或整个单词world
  • .*?- 任何零个或多个字符,尽可能少
  • K- 丢弃到目前为止匹配的所有文本
  • bhellob- 一个完整的单词hello.

注意:如果不需要字边界检查,则可以从模式中删除b

如果helloworld是用户定义的模式,则必须在模式中preg_quote它们:

$start = "world";
$find = "hello";
$text = "blah blah blahnhellonblah blah blahnclass="world" nblah blah blahnhello nblah blahnhellonblah blah blahnhellonblah blah blah";
echo preg_match_all('~(?:G(?!^)|' . preg_quote($start, '~') . 'b).*?K' . preg_quote($find, '~') . '~s', $text);

其他方法:强制模式失败,如果字符串中不存在world则不重试:

~(?:A(*COMMIT).*?world)?.*?hello~s

演示

非捕获组是可选的,但贪婪。因此,每次尝试该模式时都会对其进行测试。
它以与字符串开头匹配的A锚点开头,因此这是该组可以成功的唯一位置。字符串开始后,在其他位置A失败,并且由于该组是可选的,因此忽略其中的其余子模式,研究继续进行.*?hello
紧接着,有回溯控制动词(*COMMIT),如果之后失败,则强制根本不重试模式。(故事完)。

换句话说,如果这个小组在字符串开始时失败,研究就会一劳永逸地中止。

优点:它比基于G的模式需要更少的步骤。


为了提高效率,也可以这样编写基于G的模式(使用可选组而不是交替):

~(?:A.*?world)?(?!A).*?hello~sA

在这里,A 修饰符扮演G锚点的角色,但它与使用G锚点启动模式的每个分支(此处只有一个)完全相同。

一种方法可能是首先剥离字符串的前导部分,直到并包括第一次出现world。 然后像您已经做的那样调用preg_match_all并获取hello的发生次数。

$input = "blah blah blah
hello
blah blah blah
class="world" 
blah blah blah
hello 
blah blah
hello
blah blah blah
hello
blah blah blah";
$input = preg_replace("/^.*?bworld/", "", $input);
preg_match_all("/bhellob/", $input, $matches);
echo sizeof($matches[0]);  // 4

最新更新