Необходимо ли конвертировать строку в 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;
но потом решение Яна Бойда выглядит и намного приятнее!