mb_str_replace()...很慢。有什么替代方案吗?

发布于 2024-09-14 03:16:04 字数 165 浏览 7 评论 0原文

我想确保我正在运行的一些字符串替换是多字节安全的。我在网上找到了一些 mb_str_replace 函数,但它们很慢。我说的是在传递大约 500-900 字节后增加了 20%。

有什么建议吗?我正在考虑使用 preg_replace 因为它是本机的并且是编译的,所以它可能会更快。任何想法将不胜感激。

I want to make sure some string replacement's I'm running are multi byte safe. I've found a few mb_str_replace functions around the net but they're slow. I'm talking 20% increase after passing maybe 500-900 bytes through it.

Any recommendations? I'm thinking about using preg_replace as it's native and compiled in so it might be faster. Any thoughts would be appreciated.

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(4

伏妖词 2024-09-21 03:16:05

由于当有来自任何地方(utf8 或其他)的输入时,编码是一个真正的挑战,因此我更喜欢仅使用多字节安全函数。对于str_replace,我使用这个,它足够快。

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;
   }
}

As encoding is a real challenge when there are inputs from everywhere (utf8 or others), I prefer using only multibyte-safe functions. For str_replace, I am using this one which is fast enough.

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;
   }
}
筱果果 2024-09-21 03:16:05

这是我的实现,基于 Alain 的回答

/**
 * 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'));
}

Here's my implementation, based off 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;
}

His doesn't accept a character encoding, although I suppose you could set it via mb_regex_encoding.

My unit tests pass:

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'));
}
拥抱我好吗 2024-09-21 03:16:05

Top rated note on http://php.net/manual/en/ref.mbstring.php#109937 says str_replace works for multibyte strings.

时光与爱终年不遇 2024-09-21 03:16:04

正如所说,只要所有参数都是 utf-8 有效的,str_replace 在 utf-8 上下文中就可以安全使用,因为它不会在两个多字节编码字符串之间出现任何模糊匹配。如果您检查输入的有效性,则无需寻找不同的函数。

As said there, str_replace is safe to use in utf-8 contexts, as long as all parameters are utf-8 valid, because it won't be any ambiguous match between both multibyte encoded strings. If you check the validity of your input, then you have no need to look for a different function.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文