2010-08-15 28 views
6

Tôi muốn đảm bảo rằng một số thay thế chuỗi mà tôi đang chạy là an toàn nhiều byte. Tôi đã tìm thấy một vài hàm mb_str_replace trên mạng nhưng chúng chậm. Tôi đang nói tăng 20% ​​sau khi vượt qua có thể 500-900 byte thông qua nó.mb_str_replace() ... chậm. bất kỳ lựa chọn thay thế nào?

Bất kỳ đề xuất nào? Tôi đang nghĩ về việc sử dụng preg_replace vì nó có nguồn gốc và được biên dịch để nó có thể nhanh hơn. Bất kỳ suy nghĩ sẽ được đánh giá cao.

+0

Bạn cần phải cung cấp thêm thông tin. Chuỗi thay thế và mã hóa chủ đề là gì? Nếu chủ đề là UTF-8 và chuỗi thay thế nằm trong phạm vi ASCII, bạn có thể sử dụng 'str_replace'. – Artefacto

+0

Unicode đã có mặt, 15 năm nay là gì? Vẫn còn mucking với các chuỗi mb trong một vòng lặp bên trong lõi? Làm việc từ trong ra ngoài. –

Trả lời

10

Như đã nói there, str_replace an toàn để sử dụng trong ngữ cảnh utf-8, miễn là tất cả tham số đều hợp lệ-ut 8, vì nó sẽ không có bất kỳ kết quả mơ hồ nào giữa cả hai chuỗi được mã hóa nhiều byte. Nếu bạn kiểm tra tính hợp lệ của đầu vào, thì bạn không cần phải tìm một hàm khác.

+3

Điều này là sai nếu bạn đang làm việc với unicode và quan tâm đến [unicode equivalentence] (http://en.wikipedia.org/wiki/Unicode_equivalence). Trong unicode một số chuỗi byte khác nhau có thể đại diện cho cùng một ký tự. Sử dụng 'str_replace' sẽ hoạt động ** chỉ ** nếu bạn chuẩn hóa cả hai chuỗi trước tiên. – Qtax

+0

Đầu tốt, dù sao hiểu biết của tôi về "an toàn nhiều byte" là "chúng sẽ không cho bất kỳ kết quả dương nào trong khi khớp", điều thực tế có nghĩa là chúng sẽ không làm hỏng thông tin đầu ra theo ý muốn của nó. –

+0

kiểm tra liên kết được cung cấp – Trix

3

Khi mã hóa là một thách thức thực sự khi có đầu vào từ mọi nơi (utf8 hoặc những người khác), tôi chỉ thích sử dụng các hàm đa chức năng an toàn. Đối với str_replace, tôi đang sử dụng this one đủ nhanh.

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

Dưới đây là thực hiện của tôi, dựa trên 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; 
} 

ông không chấp nhận một mã hóa ký tự, mặc dù tôi giả sử bạn có thể thiết lập nó qua mb_regex_encoding.

kiểm tra đơn vị của tôi vượt qua:

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')); 
} 
Các vấn đề liên quan