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?

Foi útil?

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!

Licenciado em: CC-BY-SA com atribuição
Não afiliado a StackOverflow
scroll top