Delphi中是否需要将字符串转换为WideString?

问题描述 投票:0回答:5

我发现了一个 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;

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

delphi string widestring
5个回答
11
投票

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

来自 System.pas 中的

WCharFromChar

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

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


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: 排序时将数字视为数字,例如将“2”排在“10”之前。

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


3
投票

您的函数可能有一个 ANSI 变体(我没有检查过)。大多数 Wide API 也提供 ANSI 版本,只需将 W 后缀更改为 A,即可完成设置。在这种情况下,Windows 会透明地为您进行来回转换。

PS:这里有一篇文章描述了 StrCmpLogicalA 的缺失:http://blogs.msdn.com/joshpoley/archive/2008/04/28/strcmplogica.aspx


2
投票

使用

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 的解决方案 看起来而且更好!


0
投票

我认为如果你这样做的话,内存管理器会最好地处理它:

function AnsiNaturalCompareText(const S1, S2: string): integer;   
begin
  Result := StrCmpLogicalW(PWideChar(S1), PWideChar(S2));
end;
© www.soinside.com 2019 - 2024. All rights reserved.