如何获取Delphi中文本的字符数(而不是字节数)?

时间:2014-02-20 13:28:40

标签: delphi unicode delphi-7 charactercount

我有一个 Delphi 7 应用程序,我处理ANSI字符串,我需要计算它们的字符数(而不是字节数)。我总是知道与字符串相关联的Charset(以及代码页)。

所以,知道Charset(代码页),我目前正在使用MultiByteToWideChar来获取字符数。当Charset是中文,韩文或日文字符集之一时,它很有用,其中大多数字符长度为2个字节,只使用Length函数不会给我我想要的内容。

但是,它仍将复合字符计为两个字符,我需要将它们计为一个字符。现在,一些复合字符具有Unicode中的预合成版本,因为默认情况下使用MB_PRECOMPOSED,所以这些版本将被正确计为一个字符。但是许多字符根本不存在于预先组合中,例如希伯来语,阿拉伯语,泰语等字符,并且这些字符被计为两个。

所以问题确实是:如何将复合字符计为单个字符?我不介意将ANSI字符串转换为宽字符串来计算字符数,我已经在做了无论如何都要MultiByteToWideChar

1 个答案:

答案 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。