使用 preg_replace 截取字符串的最高效方法是什么?

4

我在查看一些代码并开始考虑使用 preg_replace 最有效的方法来截断字符串(在本例中是一个URI)。

首先 - 我意识到在这种情况下使用 preg_replace 可能有点过头了,可能会更加昂贵,并且最好使用PHP的字符串友好函数,例如substr。我知道这一点。

话虽如此,请考虑这两个不同的正则表达式:

$uri = '/one/cool/uri';    // Desired result '/one/cool'

// Using a back-reference
$parent = preg_replace('#(.*)/.*#', "$1", $uri);

// Using character class negation
$parent = preg_replace('#/[^/]+$#', '', $uri);

默认情况下,我认为在前一种情况下,创建反向引用比不创建更加昂贵,因此第二个示例更可取。但是,我开始想知道在第二个示例中使用[^/]是否比第一个示例中的相应.更昂贵,如果是,那么差距有多大?
从易读性的角度来看,我更喜欢第一个示例,而且我们正在纠结这些细节,所以在这两个示例之间我倾向于选择它(毕竟,编写易读的代码也很有价值)。但这可能只是我的个人偏好。
你有什么想法吗?

2
你似乎明白自己在问什么,那为什么不设置一个基准测试呢?我的直觉也认为否定比肯定更便宜,但这只是我的直觉。我没有数据来支持它。制造一些数据吧! - Michael Berkowski
2
请注意,第二个版本可以使用所有格量词(抑制回溯)来提高效率:#/[^/]++$# - Martin Ender
1个回答

2
我也会测量两个选项的运行时间。文档中的这些信息可能也有所帮助:

http://www.php.net/manual/en/regexp.reference.performance.php

如果你在使用主题字符串不包含换行符的模式时,最好的性能是通过设置PCRE_DOTALL或在模式中显式地锚定^.*来获得。这样可以避免PCRE扫描主题以查找换行符并重新开始。$parent = preg_replace('#^(.*)/.*#s', "$1", $uri); 可能会加速第一个选项。而第二个选项则不需要此设置:
s (PCRE_DOTALL)
如果设置了此修饰符,则模式中的点元字符匹配所有字符,包括换行符。否则,换行符将被排除在外。此修饰符相当于Perl的/s修饰符。不论是否设置了此修饰符,负类(如[^a])始终与换行符匹配,这一点与其无关。

这只对完全不匹配模式的字符串有影响。如果操作者知道每个要截断的字符串都至少包含一个斜杠,则匹配将在第一次尝试中找到。 - Martin Ender
建议进行优化的方法是避免通过换行符拆分字符串并在每个字符串上尝试模式匹配。 - Niloct
啊,好的,抱歉,说得对。我有点忽略了那一点。虽然URI很少包含换行符。但总的来说,这绝对是一个好观点。 - Martin Ender

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