Delphi 如何将包含非英语字符的unicode字符串与按字母表排序的字符串进行比较?

Delphi 如何将包含非英语字符的unicode字符串与按字母表排序的字符串进行比较?,delphi,unicode,collation,Delphi,Unicode,Collation,我试图根据数组/列表/任何数据中包含非英语字符的unicode字符串值对其进行排序,我希望它们按字母顺序正确排序 我已经写了很多代码(D2010,WinXP),我认为这些代码对于未来的国际化非常可靠,但事实并非如此。它全部使用unicodestring(string)数据类型,到目前为止,我只是将英文字符放入unicode字符串中 看来我不得不承认犯了一个非常严重的unicode错误。我和我的德国朋友谈了谈,试了一些德语的ß(ß是“ss”,字母表中应该在s之后和T之前)和andö等(注意umla

我试图根据数组/列表/任何数据中包含非英语字符的unicode字符串值对其进行排序,我希望它们按字母顺序正确排序

我已经写了很多代码(D2010,WinXP),我认为这些代码对于未来的国际化非常可靠,但事实并非如此。它全部使用unicodestring(string)数据类型,到目前为止,我只是将英文字符放入unicode字符串中

看来我不得不承认犯了一个非常严重的unicode错误。我和我的德国朋友谈了谈,试了一些德语的ß(ß是“ss”,字母表中应该在s之后和T之前)和andö等(注意umlaut),我的排序算法都不起作用了。结果非常混乱。垃圾

从那以后,我一直在广泛地阅读,学到了很多关于unicode排序的不愉快的事情。事情看起来很糟糕,比我想象的更糟,我把事情搞砸了。我希望我错过了一些东西,事实上事情并不像现在看起来的那么糟糕。我一直在修补windows api调用(RTLCompareInocDestring),但没有成功(保护故障),我无法让它工作。我学到的API调用的问题是,它们在各种较新的windows平台上都会发生变化,而且delphi很快就会跨平台运行,linux之后,我的应用程序是客户端-服务器,所以我需要关注这一点,但在这种情况下(糟糕),如果有任何进展,我将不胜感激

使用win api函数RTLCompare是否是显而易见的解决方案?如果是这样的话,我真的应该再试一次,但是我已经被unicode排序所涉及的所有问题吓了一跳,我根本不清楚我应该做什么来以这种方式比较这些字符串

我了解了IBM ICU C++的开源项目,它有一个Delphi包装器,虽然是ICU的旧版本。这似乎是一个非常全面的解决方案,与平台无关。当然,我不能指望为此创建一个delphi包装器(或更新现有的包装器)来获得一个好的unicode排序解决方案

我非常高兴听到两个层面的建议:-

A) 这是一个特定于windows的非便携解决方案,我现在很高兴,忘记客户机-服务器的影响吧! B) 一个更便携的解决方案,它不受unicode api函数的各种XP/vista/win7变体的影响,因此对XE2 mac支持和未来的linux支持都有好处,更不用说客户机-服务器复杂性了

顺便说一句,我真的不想做“凑合”的解决方案,在比较之前扫描字符串,替换某些棘手的字符等等,我已经读过了。我在上面举了一个德语的例子,这只是一个例子,我想让它适用于所有语言(或者至少大多数,远东,俄语),我不想为一两种特定的语言做变通。我也不需要任何关于排序算法的建议,它们很好,只是字符串比较位出错

我希望我错过了/做了一些愚蠢的事情,这一切看起来都令人头痛

多谢各位


编辑,鲁迪,这是我如何打电话给RTLCompating的。很抱歉耽搁了我这段时间过得很糟糕

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个测试字符串(空格分隔-没有字符串包含空格):-

  • 阿尔萨斯·阿斯·阿斯·阿斯·诺斯·奥斯·奥斯·奥斯·奥斯·奥斯·奥斯·奥斯·奥斯·奥斯·奥斯·奥斯·奥斯·奥斯·奥斯·奥斯·奥斯·奥斯·奥斯·奥斯·奥斯·奥斯·奥斯·奥斯·奥斯·奥斯·奥斯·奥斯·奥斯·奥斯·奥斯·奥斯·奥斯·奥斯·奥斯 Sßbßßssss ssssßßSßSßSßzßz zzz

编辑2

我仍然很想知道AnsiCompareText是否应该像lkessler所说的那样使用区域设置信息,lkessler以前也发布过关于这些主题的文章,而且似乎以前也经历过

然而,根据Rudy的建议,我也检查了CompareStringW——它与共享相同的文档,因此它不是我前面提到的非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);
现在,你可以想象我的沮丧,当我仍然得到同样的排序结果,因为我做的权利在开始

  • 阿尔阿斯阿斯阿斯阿斯阿斯阿斯诺诺诺奥奥奥奥奥奥奥波普斯斯斯斯斯斯斯斯斯阿斯阿斯 Sßbßßssss ssssßßSßSßSßzßz zzz
你也可以想象,当我意识到排序顺序是正确的,而且在乞讨中也是正确的时,我极度的沮丧,更不用说同时的喜悦了!这让我恶心