在PHP中计算带有半宽假名的日文多字节字符串的长度


Calculating the length of a Japanese multibyte string with half-width kana in PHP

所以我有一个UTF-8编码的字符串,可以包含全宽汉字,全宽假名,半宽假名,romaji,数字或kawaii日语符号,如★或♥。

如果我想要长度,我用mb_strlen(),它把每一个的长度都算作1。这在大多数情况下是可以的。

但是,一个日本客户要求我只把半宽假名算为0.5(为了文本字段的最大长度),因为很明显日本网站就是这样做的。我使用mb_strwidth()将全宽计为2,半宽计为1,然后我只需除以2。

然而,这种方法也将罗马字符计数为1,因此像Chocアイス这样的字符将计数为7 ..然后再除以2,得到3.5。但我实际上想要5.5 (Romaji为4 + 3半宽假名为1.5)。

//编辑:一些更多的信息:任何字符(即使是非假名),这两个全和半应该是1的全宽和0.5的半宽。例如,像¥、3@(这样的字符应该都是1,但像¥,3@(这样的字符应该都是0.5

//EXTRA EDIT:像☆和♥这样的符号应该是1,但是mb_strwidth/2方法返回它们为0.5

日文系统是否有计算字符串长度的标准方法?或者每个人都只是循环遍历他们的字符串并计算不符合标准宽度规则的字符?

一种方法是将半宽片假名转换为全宽片假名,并从原始长度中减去宽度差:

$raw = 'Chocアイス';
$full = mb_convert_kana($raw, 'K');
$len = mb_strlen($raw) - (mb_strwidth($full) - mb_strwidth($raw))/2;
assert($len === 5.5);

然而,你确定你应该考虑基本拉丁字符全宽吗?也确实存在全宽的基本拉丁字符变体——也就是说,Choc应该被认为与Choc相同吗?

通常,像"A"answers"这样的字符的宽度为1,但"A"answers"的宽度为2(这就是mb_strwidth所做的)。如果我要破解这个问题,我会很谨慎的。


给定您的编辑mb_strwidth(或mb_strwidth/2)完全符合您的要求。

所以,我找不到答案。

我通过逐字遍历并检查每个字符并手动应用我的客户要求的计数规则来修复它。

看看Perl的Unicode::GCString模块:它给出了所有Unicode的正确列,包括东亚的东西。

它是Unicode::LineBreak的底层组件,我发现它对于亚洲脚本进行适当的文本分割是绝对不可或缺的。

你可以想象,两者都是Made in Japan™。:)