preg_offset_capture子数组的顺序是否*保证*是递增偏移量?

13

我无法找到权威的答案,尽管我99.9%确定这是正确的。像接受的答案依赖于它是真实的,因为我预计其他很多代码也会这样做。但是,真正了解preg_match_all(不是通过观察而是通过规定要求或规定算法)的人能否确认这是保证的行为?我无法从文档中得出结论。

我的使用情况非常简单:

preg_match_all("/$regexp/", $content, $matches, PREG_OFFSET_CAPTURE);

我知道$regexp不包含任何子模式,所以文档告诉我,$matches[0]将是一个由2元素数组组成的数组,其中每个子数组具有数值键0,包含匹配模式的字符串,以及数值键1,包含匹配发生在$content中的偏移量。虽然只有数组元素按偏移量递增排序似乎是合理的,但我看不到这是必需的,如果不是这种情况就会出现bug。虽然我无法想象如何才能做到有效地实现它,也许有一些方法可以使用多线程实现preg_match_all,将其部分结果附加而不合并成完全排序的顺序。

在我的情况下,我只关心偏移量,而不关心匹配的字符串,但偏移量递增非常重要。所以,我采用了保守的编码方式:

preg_match_all("/$regexp/", $content, $matches, PREG_OFFSET_CAPTURE);
$offsets = array();
foreach ($matches as $match) {
    $offsets[] = $match[1];
}
sort($offsets);

换句话说,最终的sort($offsets)是否肯定是浪费循环次数?

如果问一个相关但可能是单独问题不会让我陷入麻烦,那么假设排序是有用的,采用默认的SORT_REGULAR标志如所示,还是明确指定SORT_NUMERIC标志更有效率,因为preg_match_all中产生的偏移量必须是数字?


有趣的问题。(本来有答案,但太急了,在读完整个问题之前就讲出来了——哎呀!) - ridgerunner
有人需要查看 php源代码 :) - zx81
我真的不太理解这个问题。每个匹配项都是一个数组元素,也是仅包含2个元素(匹配字符串[0]及其偏移量[1])的数组。我认为偏移量不是按照单个数组中的顺序排序的。尽管这种行为可能会随其他标志的组合而改变,但由于它是按顺序构建的,很难想象任何无序的结果。在正则表达式中,堆栈被广泛地用于维护位置上下文。 - user557597
@sln 问题说明没有子模式。结果是一个只有一个元素的数组,而这个元素是一个包含每个匹配整个模式在主题内的字符串和偏移量的两个元素数组的数组。那么问题是两个元素数组的顺序是否被指定为按递增偏移值排序。似乎没有指定顺序,但当前的PHP实现保证它会这样做。 - sootsnoot
@sootsnoot - 实际上,任何引擎找到的顺序都是从左到右连续的。它遵循解析表达式时发现的相同顺序。因此,在每个子表达式中,偏移量必须始终大于或等于其子表达式前驱。因此,每个匹配只需将其结果附加到其相应的表达式元素中即可。顺便说一句,回溯是这里的800磅大猩猩。在这种情况下协调线程不是微不足道的(我的意见)。 - user557597
@sln 我同意一般情况下,带有量词的正则表达式会使得线程的有效使用变得不切实际。然而,一个实现可以检查表达式和主题字符串,以确定线程可能有益的特殊情况。例如,一个由单个普通字符组成的正则表达式和一个多兆字节的主题字符串。在这种情况下,将主题分成几个段并并行运行扫描可能是值得的,即使考虑到开销。要求按偏移量排序的结果可能会增加开销。 - sootsnoot
1个回答

6
关于您提出的关于字符串偏移量顺序的问题:
完全匹配应始终按升序排列字符串偏移量。 PHP使用循环来实现全局匹配,该循环将start_offset设置为最近完全匹配的末尾,直到主题字符串的结尾。 也就是说,它先找到第一个匹配项,然后找到第二个匹配项,再找到第三个匹配项,以此类推。
如果您想验证我没有误读源代码(或遗漏了重要的东西),您可以查看ext / pcre / php_pcre.c中的php_pcre_match_impl函数。 preg_match_all将全局参数设为1。 提示我注意到的是global的do while循环的末尾的注释:
/*Advance to the position right after the last full match*/
start_offset = offsets[1];

如果设置了全局变量,则循环将使用新的偏移量重复,并再次调用pcre_exec
关于您的SORT_NUMERIC问题:
很难说。设置SORT_NUMERIC使得排序使用numeric_compare_function进行元素比较,而SORT_REGULAR则使用compare_functioncompare_function执行类型检查,然后根据情况决定如何进行比较,而numeric_compare_function只是盲目地将两者转换为double。由于两者都是LONG,compare_function仅对它们进行比较,而不进行任何转换。因此,最终取决于哪种方法更快:盲目转换为double还是执行类型检查。

我将此标记为已接受的答案,因为它完全解释了信息来源。它并没有按照我所问的问题回答,我想知道是否指定了排序顺序。看起来并没有,因此聪明的php实现者可以决定针对长主题中的简单字符串模式优化现有代码,通过将主题分成段并在不排序最终结果的情况下并行搜索。但是,考虑到当前的实现和使用情况,这可能不会被接受。SORT_NUMERIC的好答案! - sootsnoot

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