PHP preg_replace如何替换两个或两个以上的下划线?

5

使用preg_replace,如何将多个下划线替换为一个下划线?

7个回答

21

+ 运算符(量词) 匹配最后一个字符(或字符类或捕获组或反向引用)的多个实例。

$string = preg_replace('/_+/', '_', $string);

这会将一个或多个下划线替换为一个下划线。


从技术上讲,更符合问题标题的做法是仅替换两个或更多下划线:

$string = preg_replace('/__+/', '_', $string);

或使用花括号写量词:

$string = preg_replace('/_{2,}/', '_', $string);

也许可以尝试去 捕获 然后使用(反向引用-):

$string = preg_replace('/(_)\1+/', '\1', $string);

8
preg_replace('/[_]+/', '_', $your_string);

3
这里不需要字符类。对这个答案进行一些解释会是一个不错的补充。 - mickmackusa

8

实际上,使用/__+//_{2,}/比使用/_+/更好,因为单个下划线不需要被替换。这将提高preg变量的速度。


7

运行测试,我发现了这个问题:

while (strpos($str, '__') !== false) {
    $str = str_replace('__', '_', $str);
}

要始终比这个更快:
$str = preg_replace('/[_]+/', '_', $str);

我使用以下代码生成了长度各异的测试字符串:

$chars = array_merge(array_fill(0, 50, '_'), range('a', 'z'));
$str = '';
for ($i = 0; $i < $len; $i++) {  // $len varied from 10 to 1000000
    $str .= $chars[array_rand($chars)];
}
file_put_contents('test_str.txt', $str);

并使用这些脚本进行测试(分别运行,但对于每个$len的值都使用相同的字符串):

$str = file_get_contents('test_str.txt');
$start = microtime(true);
$str = preg_replace('/[_]+/', '_', $str);
echo microtime(true) - $start;

并且:

$str = file_get_contents('test_str.txt');
$start = microtime(true);
while (strpos($str, '__') !== false) {
    $str = str_replace('__', '_', $str);
}
echo microtime(true) - $start;

对于较短的字符串,str_replace()方法比preg_replace()方法快25%左右。字符串越长,差异越小,但str_replace()始终更快。

我知道有些人可能因为其他原因而更喜欢一种方法,而不是速度,我很乐意阅读有关结果、测试方法等方面的评论。


2
对于那些因为基准测试/微优化而被@GZipp的答案所吸引的人,我认为以下后测试循环比前测试while()循环执行略好,因为已经删除了strpos()调用。 str_replace()有一个引用变量参数,可以用来在不需要额外迭代函数调用的情况下跳出循环。尽管它总是会尝试进行至少一次替换,并且只有在没有替换的情况下才会停止遍历字符串。
代码:(演示)
$str = 'one_two__three___four____bye';
do {
    $str = str_replace('__', '_', $str, $count);
} while ($count);

var_export($str);
// 'one_two_three_four_bye'

关于 preg_replace(),这里有几个不错的选项:
echo preg_replace('/_{2,}/', '_', $str);
echo preg_replace('/_\K_+/', '', $str);  // \K forgets the first, remembers the rest

我不建议使用+,因为它会造成不必要的替换(_变成了_)。
echo preg_replace('/_+/', '_', $str);

使用字符类 /[_]+//[_]{2,}/ 绝对没有好处。

使用 preg_replace() 的好处是字符串只被遍历一次。这使它成为一个非常直接和适当的工具。


0

preg_replace()

需要使用加号运算符

$text = "______";
$text = preg_replace('/[_]+/','_',$text);

3
无需定义字符类。 - gnud
非常正确,但我还是会这样做。而且似乎我并不孤单。 - Peter Lindqvist

0

您还可以使用 T-Regx 库,它具有自动分隔符功能。

pattern('_+')->replace($your_string)->with('_');

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