是否有必要在Delphi中将字符串转换为WideString?

时间:2009-06-21 18:50:30

标签: delphi string widestring

我找到了一个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;

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

4 个答案:

答案 0 :(得分:11)

请记住,将字符串转换为WideString会使用默认系统代码页转换它,这可能是您需要的,也可能不是。通常,您需要使用当前用户的区域设置。

来自System.pas中的WCharFromChar

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

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

答案 1 :(得分:5)

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

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

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

因为WideString变量指向WideChar的指针(与AnsiString变量 指针的方式相同到AnsiChar。)

这样Delphi会自动将AnsiString“上转换”为WideString

更新

既然我们现在处于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;

当您尝试将AnsiString传递给一个带UnicodeString的函数时,编译器会在生成的代码中自动为您调用MultiByteToWideChar

CompareString支持Windows 7中的数字排序

从Windows 7开始,Microsoft将SORT_DIGITSASNUMBERS添加到CompareString

  

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

这些都无法解答实际问题,该问题涉及何时必须转换或投射字符串。

答案 2 :(得分:3)

您的函数可能有一个ANSI变体(我没有检查过)。大多数Wide API也可以作为ANSI版本使用,只需将W后缀更改为A,即可设置。在这种情况下,Windows会为您进行交互式转换。

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

答案 3 :(得分:2)

使用System.StringToOleStr,这是MultiByteToWideChar周围的便捷包装,请参阅Gabr's answer

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's solution看起来更好!