我有一个 Delphi 7 应用程序,我处理ANSI字符串,我需要计算它们的字符数(而不是字节数)。我总是知道与字符串相关联的Charset(以及代码页)。
所以,知道Charset(代码页),我目前正在使用MultiByteToWideChar
来获取字符数。当Charset是中文,韩文或日文字符集之一时,它很有用,其中大多数字符长度为2个字节,只使用Length
函数不会给我我想要的内容。
但是,它仍将复合字符计为两个字符,我需要将它们计为一个字符。现在,一些复合字符具有Unicode中的预合成版本,因为默认情况下使用MB_PRECOMPOSED
,所以这些版本将被正确计为一个字符。但是许多字符根本不存在于预先组合中,例如希伯来语,阿拉伯语,泰语等字符,并且这些字符被计为两个。
所以问题确实是:如何将复合字符计为单个字符?我不介意将ANSI字符串转换为宽字符串来计算字符数,我已经在做了无论如何都要MultiByteToWideChar
。
答案 0 :(得分:2)
您可以像这样计算Unicode代码点:
function CodePointCount(P: PWideChar): Integer;
var
Count: Integer;
begin
Count := 0;
while Word(P^)<>0 do
begin
if (Word(P^)>=$D800) and (Word(P^)<=$DFFF) then
// part of surrogate pair
inc(Count)
else
inc(Count, 2);
inc(P);
end;
Result := Count div 2;
end;
这涵盖了您未提及的问题。即,UTF-16是可变宽度编码。
但是,这不会告诉您UTF-16字符串表示的字形数。那是因为一些代码点代表组合字符。这些组合字符与其邻居组合以形成单个等效字符。所以,多个代码点,单个字形。可以在此处找到更多信息:http://en.wikipedia.org/wiki/Unicode_equivalence
这是一个更难的问题。要解决这个问题,您的代码需要完全理解每个Unicode代码点的含义。它是一个结合角色吗?它是如何结合的?真的,你需要一个专用的Unicode库。例如ICU。
我给你的另一个建议是放弃使用ANSI代码页。如果您真的关心国际化,那么您需要使用Unicode。