21

我找到了一个执行字符串“自然比较”的 Windows API 函数。定义如下:

int StrCmpLogicalW(
    LPCWSTR psz1,
    LPCWSTR psz2
);

为了在 Delphi 中使用它,我这样声明:

interface
  function StrCmpLogicalW(psz1, psz2: PWideChar): integer; stdcall;

implementation
  function StrCmpLogicalW; external 'shlwapi.dll' name 'StrCmpLogicalW';

因为它比较Unicode字符串,所以当我想比较 ANSI 字符串时,我不确定如何调用它。将字符串转换为 WideString 然后转换为 PWideChar 似乎就足够了,但是,我不知道这种方法是否正确:

function AnsiNaturalCompareText(const S1, S2: string): integer;
begin
  Result := StrCmpLogicalW(PWideChar(WideString(S1)), PWideChar(WideString(S2)));
end;

我对字符编码知之甚少,所以这就是我提出问题的原因。这个函数可以吗,还是我应该先以某种方式转换两个比较的字符串?

4

4 回答 4

11

请记住,将字符串转换为 WideString 将使用默认系统代码页将其转换,这可能是您需要的,也可能不是您需要的。通常,您希望使用当前用户的语言环境。

WCharFromCharSystem.pas 中:

Result := MultiByteToWideChar(DefaultSystemCodePage, 0, CharSource, SrcBytes,
  WCharDest, DestChars);

您可以通过调用SetMultiByteConversionCodePage来更改 DefaultSystemCodePage 。

于 2009-06-22T07:18:29.027 回答
5

完成任务的更简单方法是将函数声明为:

interface
   function StrCmpLogicalW(const sz1, sz2: WideString): Integer; stdcall;

implementation
   function StrCmpLogicalW; external 'shlwapi.dll' name 'StrCmpLogicalW';

因为WideString变量指向 a 的指针WideChar(就像AnsiString变量指向 a 的指针一样AnsiChar

这样,Delphi 会自动WideString为您将 AnsiString“上转换”为 a。

更新

而且由于我们现在处于 的世界中UnicodeString,因此您可以:

interface
   function StrCmpLogicalW(const sz1, sz2: UnicodeString): Integer; stdcall;

implementation
   function StrCmpLogicalW; external 'shlwapi.dll' name 'StrCmpLogicalW';

因为UnicodeString变量仍然是指向\0\0终止字符串的指针WideChars。所以如果你打电话:

var
    s1, s1: AnsiString;
begin
    s1 := 'Hello';
    s2 := 'world';

    nCompare := StrCmpLogicalW(s1, s2);
end;

当您尝试将 a 传递给AnsiString接受 a 的函数时,编译器将在生成的代码中UnicodeString自动为您调用。MultiByteToWideChar

CompareString 支持 Windows 7 中的数字排序

从 Windows 7 开始,Microsoft 添加SORT_DIGITSASNUMBERSCompareString

Windows 7:在排序过程中将数字视为数字,例如将“2”排在“10”之前。

这些都不能帮助回答实际问题,该问题涉及何时必须转换或强制转换字符串。

于 2012-05-03T18:32:44.930 回答
3

您的函数可能有一个 ANSI 变体(我尚未检查)。大多数 Wide API 也可以作为 ANSI 版本使用,只需将 W 后缀更改为 A,就可以了。在这种情况下,Windows 会透明地为您进行来回转换。

PS:这是一篇描述缺少 StrCmpLogicalA 的文章:http: //blogs.msdn.com/joshpoley/archive/2008/04/28/strcmplogicala.aspx

于 2009-06-21T19:22:10.997 回答
2

Use System.StringToOleStr,这是一个方便的包装器MultiByteToWideChar,请参阅Gabr 的回答

function AnsiNaturalCompareText(const S1, S2: string): integer;   
var
  W1: PWideChar;
  W2: PWideChar;
begin
  W1 := StringToOleStr(S1);
  W2 := StringToOleStr(S2);
  Result := StrCmpLogicalW(W1, W2);
  SysFreeString(W1);
  SysFreeString(W2);
end;

但是,Ian Boyd 的解决方案看起来更好!

于 2012-04-20T18:03:21.993 回答