【发布时间】:2011-10-26 10:49:15
【问题描述】:
我正在尝试根据其中包含非英语字符的 unicode 字符串值对数组/列表/任何数据进行排序,我希望它们按字母顺序正确排序。
我已经编写了很多代码(D2010,win XP),我认为这些代码对于未来的国际化来说非常可靠,但事实并非如此。它全部使用 unicodestring(字符串)数据类型,到目前为止,我只是将英文字符放入 unicode 字符串中。
看来我必须承认犯了一个非常严重的 unicode 错误。我和我的德国朋友交谈,并尝试了一些德语 ß,(ß 是 'ss',应该在字母表中的 S 和 T 之前)和 ö 等(注意变音符号),我的排序算法都不再起作用了。结果非常混乱。垃圾。
从那时起,我一直在广泛阅读并了解了很多关于 unicode 排序规则的不愉快的事情。事情看起来很严峻,比我想象的要严峻得多,我把这件事搞砸了。我希望我遗漏了一些东西,而事情实际上并不像现在看起来那么严峻。我一直在修补查看 windows api 调用 (RtlCompareUnicodeString) 没有成功(保护错误),我无法让它工作。我了解到的 API 调用的问题是它们在各种较新的 Windows 平台上发生了变化,而且随着 delphi 即将跨平台,后来使用 linux,我的应用程序是客户端服务器,所以我需要关注这一点,但情况是这样是不是(坏的)我会感谢任何前进的进步,即 win api specific.
是否使用win api 函数RtlCompareUnicodeString 来明显的解决方案?如果是这样,我真的应该再试一次,但是我对 unicode 排序规则所涉及的所有问题感到吃惊,而且我根本不清楚我应该怎么做才能以这种方式比较这些字符串。
我了解了 IBM ICU c++ 开源项目,它有一个 delphi 包装器,尽管它适用于旧版本的 ICU。这似乎是一个非常全面的解决方案,它独立于平台。当然,我不能考虑为此创建一个 delphi 包装器(或更新现有的包装器)以获得 unicode collation 的良好解决方案?
我很高兴听到两个层面的建议:-
A) 一个特定于 Windows 的非便携式解决方案,我现在很高兴,忘记客户端服务器的后果! B) 一个更便携的解决方案,不受各种 XP/vista/win7 unicode api 函数变体的影响,因此让我在 XE2 mac 支持和未来的 linux 支持方面处于有利地位,更不用说客户端服务器的复杂性了。
顺便说一句,我真的不想做'make-do'解决方案,在比较之前扫描字符串并替换某些我读过的棘手字符等。我在上面给出了德语示例,这只是一个示例,我想让它适用于所有(或至少大多数,远东,俄语)语言,我不想为一两种特定语言做变通方法。我也不需要任何关于排序算法的建议,它们很好,只是字符串比较位错了。
我希望我错过/做了一些愚蠢的事情,这一切看起来都很头疼。
谢谢。
编辑,Rudy,这就是我尝试调用 RtlCompareUnicodeString 的方式。很抱歉耽搁了我的时间。
program Project26
{$APPTYPE CONSOLE}
uses
SysUtils;
var
a,b:ansistring;
k,l:string;
x,y:widestring;
r:integer;
procedure RtlInitUnicodeString(
DestinationString:pstring;
SourceString:pwidechar) stdcall; external 'NTDLL';
function RtlCompareUnicodeString(
String1:pstring;
String2:pstring;
CaseInSensitive:boolean
):integer stdcall; external 'NTDLL';
begin
x:='wef';
y:='fsd';
RtlInitUnicodeString(@k, pwidechar(x));
RtlInitUnicodeString(@l, pwidechar(y));
r:=RtlCompareUnicodeString(@k,@l,false);
writeln(r);
readln;
end.
我意识到这很可能是错误的,我不习惯直接调用 api 函数,这是我最好的猜测。
关于您的 StringCompareEx api 函数。这看起来非常好,但仅适用于 Vista +,我使用的是 XP。 StringCompare 在 XP 上,但那不是 Unicode!
回顾一下,正在进行的基本任务是比较两个字符串,并根据当前 Windows 语言环境中指定的字符排序顺序进行比较。
谁能确定 ansicomparetext 是否应该这样做?它对我不起作用,但是其他人说应该这样做,而我读过的其他内容表明应该这样做。
这是我在德语语言环境中使用 AnsiCompareText 时得到的 31 个测试字符串(空格分隔 - 没有字符串包含空格):-
- arß Asß asß aßs no nö ö ön oo öö oöo öoö öp pö ss SS ßaß ßbß sß Sßa Sßb ßß ssss SSSS ßßß ssßß SSßß ßz ßzß z zzz
编辑 2。
我仍然很想知道我是否应该期望 AnsiCompareText 使用区域设置信息来工作,正如 lkessler 所说的那样,lkessler 之前也发布过关于这些主题的帖子,而且似乎之前已经经历过。
但是,根据 Rudy 的建议,我也一直在检查 CompareStringW - 它与 CompareString 共享相同的文档,因此它不是我之前所说的非 unicode。
即使 AnsiCompareText 不起作用,虽然我认为它应该起作用,但 win32api 函数 CompareStringW 确实应该起作用。现在我已经定义了我的 API 函数,我可以调用它,我得到了一个结果,并且没有错误......但是无论输入字符串如何,我每次都会得到相同的结果!它每次都返回 1 - 这意味着小于。这是我的代码
var
k,l:string;
function CompareStringW(
Locale:integer;
dwCmpFlags:longword;
lpString1:pstring;
cchCount1:integer;
lpString2:pstring;
cchCount2:integer
):integer stdcall; external 'Kernel32.dll';
begin;
k:='zzz';
l:='xxx';
writeln(length(k));
r:=comparestringw(LOCALE_USER_DEFAULT,0,@k,3,@l,3);
writeln(r); // result is 1=less than, 2=equal, 3=greater than
readln;
end;
在经历了很多痛苦之后,我觉得我现在正在取得进展。很高兴知道 AnsiCompareText,以及我在上面的 CompareStringW api 调用中做错了什么。谢谢。
编辑 3
首先,我自己修复了对 CompareStringW 的 api 调用,当我应该执行 PString(mystring) 时,我传入了 @mystring。现在一切正常。
r:=comparestringw(LOCALE_USER_DEFAULT,0,pstring(k),-1,pstring(l),-1);
现在,当我仍然得到与开始时相同的排序结果时,你可以想象我的沮丧......
- arß asß aßs Asß no nö ö ön oo öö oöo öoö öp pö ss SS ßaß ßbß sß Sßa Sßb ßß ssss SSSS ßßß ssßß SSßß ßz ßzß z zzz
当我意识到排序顺序是正确的,而且一开始就正确时,你也可以想象我的极度沮丧,更不用说同时高兴了!说起来有点恶心,但一开始就没有任何问题——这完全是因为我缺乏德语知识。我相信排序是错误的,因为您可以看到上面的字符串以 S 开头,然后它们以 ß 开头,然后再次以 s 开头,然后返回 ß 等等。好吧,我不会说德语,但是我仍然可以清楚地看到它们没有正确排序-我的德国朋友告诉我 ß 在 S 之后和 T 之前...我错了!正在发生的事情是字符串函数(AnsiCompareText 和 winapi CompareTextW)都用 'ss' 代替每个 'ß',用正常的 'o' 代替每个 'ö'......所以如果我把上面的结果和搜索并按照我得到的描述替换...
- arss asss asss Asss no no o on oo oo ooo ooo op po ss SS ssass ssbss sss Sssa Sssb ssss ssss SSSS ssssss ssssss SSssss ssz sszss z zzz
对我来说看起来很正确!并且一直如此。
我非常感谢您提供的所有建议,非常抱歉像这样浪费您的时间。那些德语ß让我很困惑,内置的delphi函数或其他任何东西都没有错。它看起来就像有。我错误地将它们与测试数据中的正常 's' 组合在一起,任何其他字母都不会产生这种未排序的错觉!波浪形的ß让我看起来像个傻瓜! ßs!
Rudy 和 lkessler 我们都特别乐于助人,你们俩,我不得不接受 lkessler 的回答是最正确的,对不起 Rudy。
【问题讨论】:
-
+1 表示想要并尝试做正确的事情。
-
谢谢伊恩。我刚刚花了4天时间搞砸了这个!下次当我发现我的猫在追自己的尾巴时,我不会笑得那么大声......
-
@csharpdefector:很高兴你能弄明白。并感谢您的详细问题和跟进,这将在其他人遇到相同问题时提供帮助。我在 StackOverflow 上的一些问题的答案告诉我,我的理解是错误的,而这种对我的想法的纠正对我来说甚至比简单地得到我的答案更有价值。 StackOverflow 的美妙之处在于,当您完全被难住时,您通常会在几天甚至几小时内得到答案。极好的。 (是的,我是一个 SO 助推器)