É necessário converter string para wideestring em Delphi?
-
06-07-2019 - |
Pergunta
Encontrei uma função da API do Windows que executa "comparação natural" de cordas. Está definido da seguinte forma:
int StrCmpLogicalW(
LPCWSTR psz1,
LPCWSTR psz2
);
Para usá -lo em Delphi, declarei da seguinte maneira:
interface
function StrCmpLogicalW(psz1, psz2: PWideChar): integer; stdcall;
implementation
function StrCmpLogicalW; external 'shlwapi.dll' name 'StrCmpLogicalW';
Porque ele se compara Unicode Strings, não tenho certeza de como chamá -lo quando quero comparar as cordas da ANSI. Parece ser o suficiente para lançar cordas para o Wideestring e depois para o Pwidechar, no entanto, não tenho idéia se essa abordagem está correta:
function AnsiNaturalCompareText(const S1, S2: string): integer;
begin
Result := StrCmpLogicalW(PWideChar(WideString(S1)), PWideChar(WideString(S2)));
end;
Eu sei muito pouco sobre a codificação de personagens, então essa é a razão da minha pergunta. Essa função está bem ou devo converter primeiro as duas cordas comparadas de alguma forma?
Solução
Lembre -se de que lançar uma corda em um wideestring a converterá usando o codepage padrão do sistema, que pode ou não ser o que você precisa. Normalmente, você deseja usar o local do usuário atual.
A partir de WCharFromChar
em System.pas:
Result := MultiByteToWideChar(DefaultSystemCodePage, 0, CharSource, SrcBytes,
WCharDest, DestChars);
Você pode alterar o DefaultSystemCodePage ligando SetMultibyteConversionCodePage.
Outras dicas
A maneira mais fácil de realizar a tarefa seria declarar sua função como:
interface
function StrCmpLogicalW(const sz1, sz2: WideString): Integer; stdcall;
implementation
function StrCmpLogicalW; external 'shlwapi.dll' name 'StrCmpLogicalW';
Porque a WideString
variável é um ponteiro para um WideChar
(da mesma maneira um AnsiString
variável é um ponteiro para um AnsiChar
.)
E dessa maneira, Delphi "aumentará automaticamente um Ansistring para um WideString
para voce.
Atualizar
E já que agora estamos no mundo de UnicodeString
, você faria:
interface
function StrCmpLogicalW(const sz1, sz2: UnicodeString): Integer; stdcall;
implementation
function StrCmpLogicalW; external 'shlwapi.dll' name 'StrCmpLogicalW';
Porque a UnicodeString
A variável ainda é um ponteiro para um \0\0
string terminada de WideChars
. Então, se você ligar:
var
s1, s1: AnsiString;
begin
s1 := 'Hello';
s2 := 'world';
nCompare := StrCmpLogicalW(s1, s2);
end;
Quando você tenta passar um AnsiString
em uma função que leva um UnicodeString
, o compilador ligará automaticamente MultiByteToWideChar
para você no código gerado.
Comparestring suporta classificação numérica no Windows 7
A partir do Windows 7, a Microsoft adicionou SORT_DIGITSASNUMBERS
para CompareString
:
Windows 7: Trate os dígitos como números durante a classificação, por exemplo, classifique "2" antes de "10".
Nada disso ajuda a responder ao real Pergunta, que lida quando você precisa converter ou lançar cordas.
Pode haver uma variante ANSI para sua função (eu não verifiquei). A maioria das APIs amplas também está disponível como uma versão da ANSI, basta alterar o sufixo W para um A e você está definido. O Windows faz a conversão de entrada e partida de maneira transparente para você nesse caso.
PS: Aqui está um artigo que descreve a falta de strcmplogicalA: http://blogs.msdn.com/joshpoley/archive/2008/04/28/strcmplogica.aspx
Usar System.StringToOleStr
, que é uma embalagem prática ao redor MultiByteToWideChar
, Vejo Resposta de 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;
Mas então, Solução de Ian Boyd Parece e é muito melhor!