我想确保我正在运行的一些字符串替换是多字节安全的。我在网络上发现了一些mb_str_replace函数,但它们很慢。在通过500-900字节之后,我会说增加20%。mb_str_replace()...很慢。任何替代品?
有什么建议吗?我正在考虑使用preg_replace,因为它是原生的并且被编译进来,所以它可能会更快。任何想法将不胜感激。
我想确保我正在运行的一些字符串替换是多字节安全的。我在网络上发现了一些mb_str_replace函数,但它们很慢。在通过500-900字节之后,我会说增加20%。mb_str_replace()...很慢。任何替代品?
有什么建议吗?我正在考虑使用preg_replace,因为它是原生的并且被编译进来,所以它可能会更快。任何想法将不胜感激。
正如所说的there,只要所有参数都是utf-8有效,就可以安全地在utf-8上下文中使用str_replace,因为这两个多字节编码字符串之间不会有任何模糊的匹配。如果你检查输入的有效性,那么你不需要寻找一个不同的功能。
如果您使用unicode并关心[unicode equivalence](http://en.wikipedia.org/wiki/Unicode_equivalence),这是错误的。在unicode中,几个不同的字节序列可以表示相同的字符。如果你首先规范化你的两个字符串,那么使用'str_replace'只会** **。 – Qtax 2014-01-22 10:52:43
好的提示,无论如何,我对“多字节安全”的理解是“他们不会在匹配时给出任何错误肯定”,实际上意味着他们不会根据替换的期望来破坏输出信息。 – 2014-01-24 21:12:04
查询提供的链接 – Trix 2017-05-15 06:27:28
由于编码是来自任何地方(utf8或其他)的输入的真正挑战,我更喜欢只使用多字节安全函数。对于str_replace
,我使用的是this one,它足够快。
if (!function_exists('mb_str_replace'))
{
function mb_str_replace($search, $replace, $subject, &$count = 0)
{
if (!is_array($subject))
{
$searches = is_array($search) ? array_values($search) : array($search);
$replacements = is_array($replace) ? array_values($replace) : array($replace);
$replacements = array_pad($replacements, count($searches), '');
foreach ($searches as $key => $search)
{
$parts = mb_split(preg_quote($search), $subject);
$count += count($parts) - 1;
$subject = implode($replacements[$key], $parts);
}
}
else
{
foreach ($subject as $key => $value)
{
$subject[$key] = mb_str_replace($search, $replace, $value, $count);
}
}
return $subject;
}
}
这里是我的实现,基于断Alain's answer:
/**
* Replace all occurrences of the search string with the replacement string. Multibyte safe.
*
* @param string|array $search The value being searched for, otherwise known as the needle. An array may be used to designate multiple needles.
* @param string|array $replace The replacement value that replaces found search values. An array may be used to designate multiple replacements.
* @param string|array $subject The string or array being searched and replaced on, otherwise known as the haystack.
* If subject is an array, then the search and replace is performed with every entry of subject, and the return value is an array as well.
* @param string $encoding The encoding parameter is the character encoding. If it is omitted, the internal character encoding value will be used.
* @param int $count If passed, this will be set to the number of replacements performed.
* @return array|string
*/
public static function mbReplace($search, $replace, $subject, $encoding = 'auto', &$count=0) {
if(!is_array($subject)) {
$searches = is_array($search) ? array_values($search) : [$search];
$replacements = is_array($replace) ? array_values($replace) : [$replace];
$replacements = array_pad($replacements, count($searches), '');
foreach($searches as $key => $search) {
$replace = $replacements[$key];
$search_len = mb_strlen($search, $encoding);
$sb = [];
while(($offset = mb_strpos($subject, $search, 0, $encoding)) !== false) {
$sb[] = mb_substr($subject, 0, $offset, $encoding);
$subject = mb_substr($subject, $offset + $search_len, null, $encoding);
++$count;
}
$sb[] = $subject;
$subject = implode($replace, $sb);
}
} else {
foreach($subject as $key => $value) {
$subject[$key] = self::mbReplace($search, $replace, $value, $encoding, $count);
}
}
return $subject;
}
他不接受字符编码,但我想你可以通过mb_regex_encoding
设置。
我的单元测试都通过了:
function testMbReplace() {
$this->assertSame('bbb',Str::mbReplace('a','b','aaa','auto',$count1));
$this->assertSame(3,$count1);
$this->assertSame('ccc',Str::mbReplace(['a','b'],['b','c'],'aaa','auto',$count2));
$this->assertSame(6,$count2);
$this->assertSame("\xbf\x5c\x27",Str::mbReplace("\x27","\x5c\x27","\xbf\x27",'iso-8859-1'));
$this->assertSame("\xbf\x27",Str::mbReplace("\x27","\x5c\x27","\xbf\x27",'gbk'));
}
你需要给更多的信息。什么是替换字符串和主题的编码?如果主题是UTF-8,并且替换字符串在ASCII范围内,则可以使用'str_replace'。 – Artefacto 2010-08-15 23:46:33
Unicode已经存在了,15年了,现在呢?仍在使用核心内部循环中的mb字符串?从内到外工作。 – 2010-08-16 00:18:32