2014-02-20 25 views
1

我有一个德尔福7应用程序,其中我处理ANSI字符串,我需要计数其字符数(而不是字节数)。我总是知道与字符串相关的字符集(以及代码页)。如何获得Delphi中文本的字符数(而不是字节数)?

因此,知道字符集(代码页),我目前使用MultiByteToWideChar来获取字符数。当字符集是大多数字符长度为2个字节的中文,韩文或日文字符集之一,并且仅使用Length函数不会给我我想要的字符时,它非常有用。

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

所以问题的确是:如何将复合字符统计为单个字符?我不介意将ANSI字符串转换为宽字符串来计算字符数,我已经在使用MultiByteToWideChar

回答

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。

+0

'MultiByteToWideChar'已经涵盖了UTF-16是一种可变长度编码并返回与您的函数相同结果的事实。我希望可能会有另一个API函数返回字形的实际数量,并考虑到字符组合。是的,我知道我必须迁移到Unicode,但这需要很长时间,所以我需要暂时的解决方案。这个问题真的变成了:**是否有一个与Delphi 7兼容的轻量级Unicode库,并且具有获取字形数量的直接函数?**也许是Soft Gems的一个? – jedivader

+0

使用ICU。不,MultiByteToWideChar返回代码点的数量。 –

+0

然后我对'MultiByteToWideChar'有点困惑。 [文档](http://msdn.microsoft.com/en-us/library/windows/desktop/dd319072%28v=vs.85%29.aspx)说:“如果此值为0,该函数返回所需缓冲区大小,**字符**“。如果我给它中文字符,它们被正确计数。我在这里错过了什么? – jedivader

相关问题