【问题标题】:Check to see if a string is encoded as UTF-8检查字符串是否编码为 UTF-8
【发布时间】:2010-12-01 04:49:17
【问题描述】:
function seems_utf8($str) {
 $length = strlen($str);
 for ($i=0; $i < $length; $i++) {
  $c = ord($str[$i]);
  if ($c < 0x80) $n = 0; # 0bbbbbbb
  elseif (($c & 0xE0) == 0xC0) $n=1; # 110bbbbb
  elseif (($c & 0xF0) == 0xE0) $n=2; # 1110bbbb
  elseif (($c & 0xF8) == 0xF0) $n=3; # 11110bbb
  elseif (($c & 0xFC) == 0xF8) $n=4; # 111110bb
  elseif (($c & 0xFE) == 0xFC) $n=5; # 1111110b
  else return false; # Does not match any model
  for ($j=0; $j<$n; $j++) { # n bytes matching 10bbbbbb follow ?
   if ((++$i == $length) || ((ord($str[$i]) & 0xC0) != 0x80))
    return false;
  }
 }
 return true;
}

我从 Wordpress 获得了这段代码,我对此知之甚少,但我想知道该函数到底发生了什么。

如果有人知道请帮帮我?

我需要对上述代码有清晰的认识。如果逐行解释会更有帮助。

【问题讨论】:

    标签: php string encoding utf-8


    【解决方案1】:

    我使用两种方法来检查字符串是否为utf-8(视情况而定):

    mb_internal_encoding('UTF-8'); // always needed before mb_ functions, check note below
    if (mb_strlen($string) != strlen($string)) {
     /// not single byte
    }
    

    -- 或者--

    if (preg_match('!\S!u', $string)) {
     // utf8
    }
    

    对于 mb_internal_encoding - 由于 php 中的一些未知错误(版本 5.3-(尚未在 5.3 上测试过))将编码作为参数传递给 mb_ 函数不起作用,内部编码需要在使用 mb_ 函数之前设置。

    【讨论】:

    • 那么就做mb_strlen ($string, 'UTF-8')吧。
    【解决方案2】:

    该算法基本上是检查字节序列是否符合您在Wikipedia article 中看到的模式。

    for 循环将遍历$str 中的所有字节。 ord 获取当前字节的十进制数。然后对该数字的某些属性进行测试。

    如果数字小于 128 (0x80),则为单字节字符。如果等于或大于 128,则检查多字节字符的长度。这可以通过多字节字符序列的第一个字符来完成。如果第一个字节以110xxxxx 开头,则为两字节字符; 1110xxxx,三字节字符等

    我认为最神秘的部分是 ($c &amp; 0xE0) == 0xC0 这样的表达式。那就是检查二进制格式的数字是否具有某种特定的模式。我将尝试在同一个示例中解释它是如何工作的。

    由于我们针对该模式测试的所有数字都等于或大于 0x80,因此第一个字节始终为 1,因此该模式被限制为至少 1xxxxxxxx。如果我们然后与11100000 (0xE0) 进行按位与比较,我们会得到以下结果:

      1xxxxxxx
    & 11100000
    = 1xx00000
    

    所以位置 5 和 6 的位(从右侧读取,索引从 0 开始)取决于我们当前的数字是多少。要使其等于11000000,第 5 位必须是 0,第 6 位必须是 1

      1xxxxxxx
    & 11100000
    ≟ 11000000
       ↓↓
    → 110xxxxx
    

    这意味着我们数字的其他位可以是任意的:110xxxxx。这正是 Wikipedia 文章中的模式预测的两字节字符词的第一个字节。

    最后的内部for 循环是检查多字节字符的以下字节的健全性。这些都必须以10xxxxxx开头。

    【讨论】:

      【解决方案3】:

      如果您对 UTF-8 有所了解,这是一个非常简单的实现。

      function seems_utf8($str) {
       # get length, for utf8 this means bytes and not characters
       $length = strlen($str);  
      
       # we need to check each byte in the string
       for ($i=0; $i < $length; $i++) {
      
        # get the byte code 0-255 of the i-th byte
        $c = ord($str[$i]);
      
        # utf8 characters can take 1-6 bytes, how much
        # exactly is decoded in the first character if 
        # it has a character code >= 128 (highest bit set).
        # For all <= 127 the ASCII is the same as UTF8.
        # The number of bytes per character is stored in 
        # the highest bits of the first byte of the UTF8 
        # character. The bit pattern that must be matched
        # for the different length are shown as comment.
        #
        # So $n will hold the number of additonal characters
      
        if ($c < 0x80) $n = 0; # 0bbbbbbb
        elseif (($c & 0xE0) == 0xC0) $n=1; # 110bbbbb
        elseif (($c & 0xF0) == 0xE0) $n=2; # 1110bbbb
        elseif (($c & 0xF8) == 0xF0) $n=3; # 11110bbb
        elseif (($c & 0xFC) == 0xF8) $n=4; # 111110bb
        elseif (($c & 0xFE) == 0xFC) $n=5; # 1111110b
        else return false; # Does not match any model
      
        # the code now checks the following additional bytes
        # First if expression checks that the byte is really inside the
        # string and not running over the string end.
        # The second expression just check that the highest two bits of all 
        # additonal bytes are always 1 and 0 (hexadecimal 0x80)
        # which is a requirement for all additional UTF-8 bytes
      
        for ($j=0; $j<$n; $j++) { # n bytes matching 10bbbbbb follow ?
         if ((++$i == $length) || ((ord($str[$i]) & 0xC0) != 0x80))
          return false;
        }
       }
       return true;
      }
      

      顺便说一句。在 PHP 上,我假设这比 C 函数慢 50-100 倍,所以你不应该在长字符串和生产系统上真正使用它。

      【讨论】:

        【解决方案4】:

        偶然发现这篇文章,有类似的问题.. mb_detect_encoding 显示 utf-8,但 mb_check_encoding 返回 false...

        修复它,对我来说解决方案是:

         $cur_encoding = mb_detect_encoding($in_str) ;
          if($cur_encoding == "UTF-8" && mb_check_encoding($in_str,"UTF-8"))
            return $in_str;
          else
            return utf8_encode($in_str); 
        

        从那里得到它: http://board.phpbuilder.com/showthread.php?10368156-mb_check_encoding%28-in_str-quot-UTF-8-quot-%29-return-different-results

        sry 无法正确发布链接....

        【讨论】:

          猜你喜欢
          • 1970-01-01
          • 1970-01-01
          • 2011-08-09
          • 2014-03-18
          • 2016-07-18
          • 1970-01-01
          • 2018-09-07
          • 2014-01-18
          • 2021-10-11
          相关资源
          最近更新 更多