strlen()和UTF-8编码

14
假设使用 PHP 的 UTF-8 编码和 strlen() 函数,是否可能使得这个字符串长度为 4?
我只关心 strlen() 函数,不关心其他函数。
以下是该字符串: $1�2
我已经在自己的电脑上测试过,并验证了 UTF-8 编码,得到的答案是 6。
我在 strlen 的手册中没有看到任何关于为什么某些字符计算值小于一的解释,也没有在有关 UTF-8 的文献中找到相关信息。
PS: 这个问题和答案 (4) 来自我在 Ebay 上购买的 ZCE 模拟考试。

4
strlen函数计算的是字节数而不是字符数。 - Esailija
UTF-8字符是多字节字符,在使用strlen函数时,它们的长度以字节为单位计算。请使用http://php.net/manual/en/function.mb-strlen.php获取预期结果。 - Rem.co
4
UTF-8编码的字符长度可以是1到6个字节。 - Esailija
@Esailija 你说得对!我太匆忙了,抱歉。--更正-- - Rem.co
我的问题只涉及strlen()。如果我将这个字符串放入strlen()中,我的答案是6。当我运行iconv_get_encoding()时,我得到的是"UTF-8"。 - Jon Lyles
4
不准确,UTF-8字符(编码码点)最多可以有4个字节长度。 - Pavel Radzivilovsky
6个回答

22

使用 mb_strlen() 呢?

http://lt.php.net/manual/en/function.mb-strlen.php

但如果你需要使用 strlen,可以通过设置 mbstring.func_overload 指令为 2 来配置你的 Web 服务器,这样它将自动替换你脚本中使用 strlen 为 mb_strlen。


1
是的,我在其他答案中看到了 mb_strlen(),但我特别关注 strlen()。 - Jon Lyles
修正了我的答案以回答你的评论问题。 - Anton
哎呀,我不知道 mbstrung.func_overload - 启用它会破坏我的一堆代码,因为我总是假设 strlen 是以字节为单位的长度。 - thomasrutter

14

你发布的字符串长度为6个字符:$1�2(美元符号、数字1、带分音符的小写i、倒置问号、一半分数、数字2)

如果使用该字符串的UTF-8表示形式调用strlen()函数,则会得到一个长度为9的结果(虽然有多种不同长度的表示形式)。

然而,如果我们将该字符串存储为ISO 8859-1或CP1252,则会得到一个6字节长的序列,该序列作为UTF-8是合法的。将这6个字节重新解释为UTF-8会导致4个字符:$1�2(美元符号、数字1、Unicode替换字符、数字2)。也就是说,单个字符“�”的UTF-8编码与三个字符“�”的ISO-8859-1编码完全相同。

当UTF-8解码器读取的数据不是有效的UTF-8数据时,替换字符经常被插入。

看起来原始字符串经历了多重误解层面;通过对非UTF-8数据使用UTF-8解码器(生成$1�2),以及通过你用于分析该数据的任何工具(生成$1�2)。


11

需要使用多字节字符串函数mb_strlen(),例如:

mb_strlen($string, 'UTF-8');

5

很可能在问题准备和你阅读问题之间的某个过程中,一些非ASCII字符被破坏了,因此该问题最初是关于一个包含4个字符的字符串的。

当你将替换字符U+FFFD(�)用UTF-8编码,并以latin1解释结果时,会得到序列�。例如,在从文件中读取文本时,如果字节序列没有编码任何字符,则使用该字符来替换这些序列。发生的情况很可能是这样的:

原始问题存储在一个latin1文本文件中,其中包括:$1¢2(可以用任何非ASCII字符代替¢)

该文件被一个使用UTF-8的程序读取。由于无法解释对应于¢的字节,程序会替换它并读取文本$1�2。 然后,该文本使用UTF-8写出,导致在文件中出现$1\xEF\xBF\xBD2

然后,某些第三方程序以latin1格式读取该文件,并显示$1�2


2

不行。

我将采用反证法。

strlen计算的是字节数,因此,字符串中必须恰好有4个字节

UTF8编码需要每个字符至少1个字节

我们已经确定:

  1. 有4个字节
  2. 一个字符由至少1个字节表示

......然而,我们有6个字符......这是一个矛盾。所以,不行。

但是,仍不完全清楚的是,显示软件(例如,Web浏览器)使用哪种字符集来解释该字符串。它可能使用某些不常见的编码方案,其中一个字符可以由少于8位表示。如果是这种情况,则4个字节可以显示为6个字符。因此,字符串可以是utf8,但浏览器可以决定将其解释为某个5位字符集。


1
许多UTF-8字符需要多个字节而不是一个。这就是UTF-8的构造方式(这也是你可以在单个集合中拥有如此多的字符的原因)。
请尝试使用mb_strlen()代替。

趣闻:理论上,UTF-8 可以使用最多 8 个字节来表示一个字符,尽管到目前为止还没有使用到这么长的字符——最常用的长度是四个字节的一些字符(比如乐谱符号和一些中文字符)。 - oezi
strlen()怎么样?答案可能少于6吗? - Jon Lyles
@JonLyles:strlen()函数计算字符串中的字节数。如果该字符串有6个字节,则结果为6。 - Madara's Ghost

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接