不正确的多字节字符宽度

Incorrect Multi-byte Character Width

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

上下文

A class 被用来表示一个通用字符串,它既可迭代又可查找;两次迭代都适用于字符串中的字符。字符串具有完整的多字节支持,因此当寻找新位置时,它不仅存储字符位置,而且重新计算字符串中的字节位置;像这样:

$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);

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

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

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

returns 73 符合预期。

这是已知问题吗?

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

郑重声明,这是在 PHP 5.6.3 windows 环境中进行的 PHP 单元测试 运行。

您似乎误解了 mb_strwidth 的函数。它的目的与字节无关,它只是根据固定的 table 给你一个字符串的 视觉宽度 。这对于具有适当等宽字体的亚洲字符集来说非常有趣,其中拉丁字符、逗号和其他标点符号是半角的,而 "regular" 字符是全角的。包括 U+1FFF 在内的所有内容都是 1.

您需要使用 strlen 和其他编码未知函数以字节为单位对字符串进行操作,并使用 mb_ 函数在字符级别对它们进行操作,以找出您的 byte/character 关系。

如果您担心野蛮的 mb 重载,请检查 ini 设置并拒绝在疯狂的系统上运行,或者使用 mb_strlen 和单字节编码集。