Необходимо ли конвертировать строку в WideString в Delphi?

Я нашел функцию 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 strings, я не уверен, как это назвать, когда я хочу сравнить строки ANSI. Кажется, достаточно бросить строки в WideString, а затем в PWideChar, однако я понятия не имею, правильный ли этот подход:

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

I знаю очень мало о кодировке символов, так что это причина моего вопроса. Эта функция в порядке или я должен сначала преобразовать обе сравниваемые строки каким-то образом?

4 ответов


имейте в виду, что приведение строки в WideString преобразует ее, используя системную кодовую страницу по умолчанию, которая может быть или не быть тем, что вам нужно. Как правило, вы хотите использовать языковой стандарт текущего пользователя.

С WCharFromChar в системы.pas:

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

Вы можете изменить DefaultSystemCodePage, вызвав SetMultiByteConversionCodePage.


более простой способ выполнить задачу - объявить вашу функцию как:

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 переменная указатель на прекращено строку 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".

ничто из этого не помогает ответить фактический вопрос, который касается того, когда вам нужно конвертировать или отливать строки.


может быть вариант ANSI для вашей функции (я не проверял). Большинство широких API также доступны как версия ANSI, просто измените суффикс W на A, и вы настроены. В этом случае Windows выполняет преобразование туда и обратно для вас.

PS: вот статья, описывающая отсутствие StrCmpLogicalA:http://blogs.msdn.com/joshpoley/archive/2008/04/28/strcmplogicala.aspx


использовать System.StringToOleStr, который является удобной оберткой вокруг MultiByteToWideChar см. ответ Габра:

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;

но потом решение Яна Бойда выглядит и намного приятнее!