Нужно ли конвертировать строку в WideString в Delphi?
-
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);
Другие советы
Самый простой способ выполнить задачу - объявить вашу функцию следующим образом:
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;
Но тогда решение Яна Бойда выглядит и выглядит намного лучше!