【问题标题】:How do I find the number of bytes within UTF-8 string with PHP?如何使用 PHP 查找 UTF-8 字符串中的字节数?
【发布时间】:2011-01-23 23:08:54
【问题描述】:

我从 php.net 站点获得了以下函数来确定 ASCII 和 UTF-8 字符串中的字节数:

<?php 
/** 
 * Count the number of bytes of a given string. 
 * Input string is expected to be ASCII or UTF-8 encoded. 
 * Warning: the function doesn't return the number of chars 
 * in the string, but the number of bytes. 
 * 
 * @param string $str The string to compute number of bytes 
 * 
 * @return The length in bytes of the given string. 
 */ 
function strBytes($str) 
{ 
  // STRINGS ARE EXPECTED TO BE IN ASCII OR UTF-8 FORMAT 

  // Number of characters in string 
  $strlen_var = strlen($str); 

  // string bytes counter 
  $d = 0; 

 /* 
  * Iterate over every character in the string, 
  * escaping with a slash or encoding to UTF-8 where necessary 
  */ 
  for ($c = 0; $c < $strlen_var; ++$c) { 

      $ord_var_c = ord($str{$d}); 

      switch (true) { 
          case (($ord_var_c >= 0x20) && ($ord_var_c <= 0x7F)): 
              // characters U-00000000 - U-0000007F (same as ASCII) 
              $d++; 
              break; 

          case (($ord_var_c & 0xE0) == 0xC0): 
              // characters U-00000080 - U-000007FF, mask 110XXXXX 
              // see http://www.cl.cam.ac.uk/~mgk25/unicode.html#utf-8 
              $d+=2; 
              break; 

          case (($ord_var_c & 0xF0) == 0xE0): 
              // characters U-00000800 - U-0000FFFF, mask 1110XXXX 
              // see http://www.cl.cam.ac.uk/~mgk25/unicode.html#utf-8 
              $d+=3; 
              break; 

          case (($ord_var_c & 0xF8) == 0xF0): 
              // characters U-00010000 - U-001FFFFF, mask 11110XXX 
              // see http://www.cl.cam.ac.uk/~mgk25/unicode.html#utf-8 
              $d+=4; 
              break; 

          case (($ord_var_c & 0xFC) == 0xF8): 
              // characters U-00200000 - U-03FFFFFF, mask 111110XX 
              // see http://www.cl.cam.ac.uk/~mgk25/unicode.html#utf-8 
              $d+=5; 
              break; 

          case (($ord_var_c & 0xFE) == 0xFC): 
              // characters U-04000000 - U-7FFFFFFF, mask 1111110X 
              // see http://www.cl.cam.ac.uk/~mgk25/unicode.html#utf-8 
              $d+=6; 
              break; 
          default: 
            $d++;    
      } 
  } 

  return $d; 
} 
?> 

但是当我用俄语尝试这个时(例如По своей природе компьютеры могут работать лишь с числами. И для того, чтобы они могли хранить в памяти буквы или другие символы, каждому такому символу должно быть поставлено в соответствие число.)。它似乎没有返回正确的字节数。

switch 语句使用默认条件。任何想法为什么俄罗斯字符不会按预期工作?或者会有更好的选择吗?

我问这个是因为我需要将 UTF-8 字符串缩短到一定数量的字节。即我只能发送一个最大值。在我的情况下,向 iPhone APNS 发送 169 字节的 JSON 数据(不包括其他数据包数据)。

参考:PHP strlen - Manual (Paolo Comment on 10-Jan-2007 03:58)

【问题讨论】:

  • 开关(真)?这是一种奇怪的做事方式..
  • 该功能来自帖子底部参考中的评论。我没有编码 :) 但是看起来它是在正确的过程中,而不是使用 mb_strlen,除了俄语字符不起作用。
  • @Brendan 我只是在想同样的事情。
  • @BrendanLong switch(true) 有什么奇怪的地方?
  • 是吗?恕我直言,如果您有多个elseifs,您应该尽可能使用switch(),就像在OP 中一样。也许这只是我。 :)

标签: php string utf-8 byte strlen


【解决方案1】:

如果您希望在使用mbstring.func_overload 2 和UTF-8 字符串时找到多字节字符串的字节长度,那么您可以使用以下方法:

mb_strlen($utf8_string, 'latin1');

【讨论】:

  • 这不只是在字符数中给出字符串长度吗?我需要知道正在使用的实际字节数。在 utf-8 中,一个字符可以超过一个字节,对吗?
  • 根据php.net/manual/en/function.mb-strlen.php 的cmets 部分(非常底部),人们普遍认为,以所述方式调用的这个函数将计算字节数。当您告诉该函数时,您的输入字符串包含 latin1 (ergo: ascii) 字符,他可能会将每个字节都计为一个字符,尽管它可能不是 ascii 意义上的有效字符。你能试试这个吗?很抱歉没有支持 mb 的环境...
【解决方案2】:

在 PHP 5 中,mb_strlen 应该返回字符数; strlen 应该返回字节数。

比如这部分代码:

$string = 'По своей природе компьютеры могут работать лишь с числами. И для того, чтобы они могли хранить в памяти буквы или другие символы, каждому такому символу должно быть поставлено в соответствие число';
echo mb_strlen($string, 'UTF-8') . '<br />';
echo strlen($string);

应该得到以下输出:

196
359


作为旁注:这是 PHP 6 将改变的事情之一:默认情况下 PHP 6 将使用 Unicode,这意味着在 PHP 6 中 strlen 应该返回字符数,而不是字节数。

【讨论】:

  • 即使使用 PHP5,您也无法做出这样的假设。 strlen() 可能会或可能不会被 mb_strlen() 重载。调用 mb_strlen($string, 'latin1'); 更安全
  • 我在问题中提供的功能似乎适用于 utf-8。我相信我的问题出在 iPhone PUSH APNS 代码的其他地方。我似乎能够推送大约 160 字节的日文、英文文本等。但是我只能推送大约 110 字节的西里尔文(俄语)字符。
  • 我仍然认为不能依靠 strlen 和 mb_strlen 来确定实际字节数。
  • PHP 6? PHP 6? PHP 似乎不太可能“默认使用 Unicode”。
【解决方案3】:

strlen() 返回字节数。

将多字节字符串缩短为特定字节数是一项单独的任务。当你缩短它时,你需要注意不要在多字节序列的中间切断字符串。

您需要处理的另一件事是,当您将字符串放入 json 表示法时,它可能需要更多字节才能将其表示为 json。例如,如果您的字符串包含双引号字符。需要转义,反斜杠字符会加一个字节。还有其他字符也需要转义。关键是,它可以变大。我假设字节限制在总 json 有效负载上,因此您确实需要考虑 json 语法本身,以及 json 将对您的字符串施加的任何转义。

一种未优化的、有点老套的方法是使用 substr() 将字符串截断,比限制多 5 个字节。现在使用 mb_strlen() 获取字符数,使用 mb_substr() 删除最后一个字符。现在将其编码为 json,并通过 strlen() 测量字节。进入一个循环,它使用 mb_substr() 不断切断最后一个字符,编码为 json,然后再次使用 strlen() 测量字节。当字节数可接受时,循环终止。

【讨论】:

  • 我已经有一个 while 循环,它使用 mb_substr 一次切掉 1 个字符,直到字节数低于限制。 strlen,似乎返回的字节数与我的问题中的函数不同。 strlen() 可能会也可能不会像其他 cmets 一样被 mb_strlen() 重载,因此不应依赖它。
  • 所以不要超载strlen。如果你不控制它,那么还有其他方法。例如 while (isset($str[$i])) $i++;会成功的。或者 fwrite() 它到一个流什么的......
【解决方案4】:

我问这个是因为我需要缩短 一个 utf-8 字符串到一定数量的 字节。

mb_strcut() 正是这样做的,尽管您可能无法从几乎难以理解的文档中分辨出来。

【讨论】:

  • 谢谢,对于我的情况,使用 mb_strcut() 比使用 mb_substr() 更好。
【解决方案5】:

字节数字符串长度!

要获取字节数,您可以使用 (php4,5) strlen。 要获取 unicode 字符串(utf8 编码)长度,您可以使用 mb_strlen(注意该扩展的函数重载),或者您可以简单地计算所有未设置第 8 位的字节。

第 8 位表示此 unicodechar 至少还有一个字节来自输入。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2012-01-20
    • 1970-01-01
    • 2016-04-23
    • 2013-11-17
    • 2012-01-19
    • 2020-03-09
    • 2016-08-14
    • 1970-01-01
    相关资源
    最近更新 更多