Нужно ли конвертировать строку в WideString в Delphi?

StackOverflow https://stackoverflow.com/questions/1024515

  •  06-07-2019
  •  | 
  •  

Вопрос

Я обнаружил функцию 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;

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

Это было полезно?

Решение

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

Из WCharFromChar в System.pas:

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

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

Другие советы

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

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

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

Поскольку переменная WideString является указателем на WideChar (аналогично переменной AnsiString < em> является указателем на AnsiChar .)

Таким образом, Delphi автоматически "преобразует конверсию" AnsiString для WideString для вас.

Update

И так как мы сейчас находимся в мире 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".

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

Для вашей функции может быть вариант ANSI (я не проверял). Большинство Wide 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;

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

Лицензировано под: CC-BY-SA с атрибуция
Не связан с StackOverflow
scroll top