多字节字符宽度不正确

时间:2015-06-29 10:59:48

标签: php utf-8 multibyte

我在mb_strwidth函数中遇到了一些奇怪的东西;它可能是一个错误,但我认为最好先问这里,以防我错过了什么。

上下文

一个类用于表示一个通用字符串,并且是可迭代的和可搜索的;迭代和寻求应用于字符串中的字符。该字符串具有完全的多字节支持,因此当寻找新位置时,它不仅存储字符位置,而且重新计算字符串中的字节位置;像这样:

$this->posByte = mb_strwidth(
    mb_substr($this->value, 0, $pos, $this->charEncoding), 
    $this->charEncoding
)

感知错误

但是,当引入多字节字符时,返回的值不正确。测试案例如下:

$str = string('The simple sentence of the simple man; here are some multi-byte chars: Øðćă.', 'UTF-8')
$str->seek(72);

这是为了寻找第二个多字节字符'ð',但上面给出的字节计算返回72,与字符位置相同;而它应该是73,因为前面的字符'Ø'的代码点为U + 00D8;这是216的十进制,并且牢牢地在双字节字符范围内。

这是通过使用多字节无意识函数strlen()来确认的(因为我没有启用mb重载);它只是计算字符串中的字节数。这样:

$bytePos = strlen(mb_substr($this->value, 0, $pos, $this->charEncoding));

按预期返回73.

这是一个已知问题吗?

我现在可以使用strlen()作为一种解决方法,但我并不特别喜欢这样做,因为在PHP配置中启用多字节重载会导致错误再次出现;有没有人有类似问题的经验? PHP只是使用了过时的字符映射吗?

对于记录,这是来自在PHP 5.6.3 Windows环境中运行的PHPUnit测试。

1 个答案:

答案 0 :(得分:1)

您似乎误解了mb_strwidth的功能。它的目的与字节无关,它只是根据固定的表格给出字符串的视觉宽度。对于具有适当的等宽字体的亚洲字符集,这是非常有趣的,其中拉丁字符,逗号和其他标点是半宽,“常规”字符是全宽。包括U + 1FFF在内的所有内容均为1

您需要使用strlen和其他编码不知道的函数来操作字符串中的字符串,并使用mb_函数在字符级别上对它们进行操作,以找出您的字节/字符关系。

如果您担心野蛮的mb-overloading,请检查insi设置并拒绝疯狂系统上的操作,或者使用mb_strlen使用单字节编码集。