将多个匹配正则表达式合并成一个,并获取匹配的结果。

4

我有一系列的正则表达式:

suresnes|suresne|surenes|surene
pommier|pommiers
^musique$
^(faq|aide)$
^(file )?loss( )?less$
paris
faq                              <<< this match twice

我的使用情况是,每个匹配到的模式都要显示一个链接给我的用户, 这样我就可以有多个模式匹配。
我会针对一个简单的文本字符串进行这些模式的测试,例如“住在巴黎”/“FAQ”/“POM”等等。
最简单的方法是使用preg_match循环遍历所有的模式,但是由于我的页面性能很重要,所以这种方法看起来不太好。
下面是我尝试过的方法:将所有这些表达式与组名组合在一起。
preg_match("@(?P<group1>^(faq|aide|todo|paris)$)|(?P<group2>(paris)$)@im", "paris", $groups);

从上面可以看到,每个模式都被分组:(?P<GROUPNAME>PATTERN),并且它们都通过竖杠|进行分隔。

结果并不是我期望的,因为只返回了第一个匹配的组。似乎当匹配发生时,解析就停止了。

我想要的是所有匹配组的列表。preg_match_all也没有用。

谢谢!


1
我想要的是所有匹配组的列表。"preg_match_all"会为每个匹配提供捕获组的列表。 - Loamhoof
我已经尝试过,只有第一个返回了匹配。 - Damien
$groups[0] 应该包含一个等同于匹配列表的数组。$groups['group1'] 将包含与第一组匹配项相同长度的列表。对于 group2 也是如此。已测试,它可以正常工作。另外,如果您担心性能问题,请检查 原子组 - Loamhoof
Damien是正确的,我没有看到使用preg_match_all来完成这个任务的简单方法,因为它只会返回第一个匹配组的匹配结果。 - soju
3个回答

7
如何呢:
preg_match("@(?=(?P<group1>^(faq|aide|todo|paris)$))(?=(?P<group2>(paris)$))@im", "paris", $groups);
print_r($groups);

输出:

Array
(
    [0] => 
    [group1] => paris
    [1] => paris
    [2] => paris
    [group2] => paris
    [3] => paris
    [4] => paris
)

(?= )被称为前瞻

正则表达式的解释:

(?=                                     # start lookahead
    (?P<group1>                         # start named group group1
        ^                               # start of string
            (                           # start catpure group #1
                faq|aide|todo|paris     # match any of faq, aide, todo or paris
            )                           # end capture group #1
        $                               # end of string
    )                                   # end of named group group1
)                                       # end of lookahead
(?=                                     # start lookahead
    (?P<group2>                         # start named group group2
            (                           # start catpure group #2
            paris                       # paris
        )                               # end capture group #2
        $                               # end of string
    )                                   # end of named group group2
)                                       # end of lookahead

看起来它工作了!你能解释一下这个语法吗?现在没有管道了,我不知道?=()是什么意思...谢谢! - Damien
@Damien:我已经添加了一个解释。 - Toto

1

Try this approach:

#/ define input string
$str_1 = "{STRING HERE}";

#/ Define regex array
$reg_arr = array(
'suresnes|suresne|surenes|surene',
'pommier|pommiers',
'^musique$',
'^(faq|aide)$',
'^(file )?loss( )?less$',
'paris',
'faq'
);

#/ define a callback function to process Regex array
function cb_reg($reg_t)
{
    global $str_1;
    if(preg_match("/{$reg_t}/ims", $str_1, $matches)){
    return $matches[1]; //replace regex pattern with the result of matching is the key trick here
    //or return $matches[0]; if you dont want to get captured parenthesized subpatterns
    //or you could return an array of both. its up to you how to do it.
    }else{
    return '';
    }
}

#/ Apply array Regex via much faster function (instead of a loop)
$results = array_map('cb_reg', $reg_arr); //returns regex results
$results = array_diff($results, array('')); //remove empty values returned

基本上,这是我能想到的最快的方法。

  1. 你不能将100个正则表达式合并为一个调用,因为它将是非常复杂的正则表达式,并且有几次匹配失败的机会。这是其中一种最好的方法。

  2. 在我看来,如果可能的话,将大量的正则表达式合并为1个正则表达式将比使用 preg_match 执行更慢,相比之下,这种 Callback 方式在 php 中处理数组是最快的方法。

还要注意, 数组上的回调不等于循环数组。循环速度较慢,并且具有算法分析中的n。但数组元素上的回调是内部的,并且与此相比非常快。


这是我能想到的最快的方法。另外, 1)您不能将100个正则表达式组合成一个调用,因为它将是非常复杂的正则表达式构建,并且匹配失败的机会很少。这是其中一种最好的方法。2)在我看来,如果可能实现将许多正则表达式组合成1个正则表达式,则与此方法相比,使用preg_match执行速度会更慢。 - Raheel Hasan
只需记住这里的关键是数组回调函数,这是在PHP中处理数组及类似情况的最快方法。 - Raheel Hasan
你应该在你的回答中加入这个解释,一个有效的回答可以是“这是不可能的,只能循环遍历模式”,但我想知道为什么 :) 谢谢! - Damien
实际上,“回调”不是“循环”!:D 循环慢且在算法分析中有一个“n”。但是对数组元素的回调是内部的,与之相比非常快。 - Raheel Hasan
完成。已将翻译文本添加到答案中。 - Raheel Hasan
显示剩余2条评论

0

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接