Pregunta

Encontré una función API de Windows que realiza "comparación natural" de cuerdas. Se define de la siguiente manera:

int StrCmpLogicalW(
    LPCWSTR psz1,
    LPCWSTR psz2
);

Para usarlo en Delphi, lo declare de esta manera:

interface
  function StrCmpLogicalW(psz1, psz2: PWideChar): integer; stdcall;

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

Debido a que compara cadenas Unicode , no estoy seguro de cómo llamarlo cuando desea comparar cadenas ANSI. Parece ser suficiente para transmitir cadenas a WideString y luego a PWideChar, sin embargo, no tengo idea de si este enfoque es correcto:

function AnsiNaturalCompareText(const S1, S2: string): integer;
begin
  Result := StrCmpLogicalW(PWideChar(WideString(S1)), PWideChar(WideString(S2)));
end;

Sé muy poco acerca de la codificación de caracteres, así que esta es la razón de mi pregunta. ¿Está bien esta función o debo convertir primero las cadenas comparadas de alguna manera?

¿Fue útil?

Solución

Tenga en cuenta que al convertir una cadena a WideString se convertirá utilizando la página de códigos predeterminada del sistema, que puede o no ser lo que necesita. Por lo general, desearía utilizar la configuración regional del usuario actual.

Desde WCharFromChar en System.pas:

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

Puede cambiar DefaultSystemCodePage llamando a

Otros consejos

La forma más fácil de realizar la tarea sería declarar su función como:

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

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

Porque una variable WideString es un puntero a una WideChar (de la misma manera que una variable AnsiString < em> es un puntero a un AnsiChar .)

Y así, Delphi convertirá automáticamente "up-convert" un AnsiString a un WideString para usted.

Actualizar

Y como ahora estamos en el mundo de UnicodeString , lo harías:

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

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

Porque una variable UnicodeString sigue siendo un puntero a una cadena terminada con \ 0 \ 0 de WideChars . Entonces, si llamas:

var
    s1, s1: AnsiString;
begin
    s1 := 'Hello';
    s2 := 'world';

    nCompare := StrCmpLogicalW(s1, s2);
end;

Cuando intentas pasar un AnsiString a una función que toma un UnicodeString , el compilador llamará automáticamente a MultiByteToWideChar en el archivo generado código.

CompareString admite la ordenación numérica en Windows 7

A partir de Windows 7, Microsoft agregó SORT_DIGITSASNUMBERS a CompareString :

  

Windows 7: trate los dígitos como números durante la clasificación, por ejemplo, clasifique " 2 " antes de " 10 " ;.

Nada de esto ayuda a responder la pregunta real , que trata cuando tiene que convertir o emitir cadenas.

Puede haber una variante ANSI para su función (no lo he verificado). La mayoría de las API anchas también están disponibles como versión ANSI, solo cambie el sufijo W a A y estará listo. Windows realiza la conversión de ida y vuelta de forma transparente para usted en ese caso.

PD: Aquí hay un artículo que describe la falta de StrCmpLogicalA: http://blogs.msdn.com/joshpoley/archive/2008/04/28/strcmplogicala.aspx

Use System.StringToOleStr , que es una práctica envoltura alrededor de MultiByteToWideChar , consulte respuesta 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;

Pero entonces, ¡La solución de Ian Boyd se ve y es mucho mejor!

Licenciado bajo: CC-BY-SA con atribución
No afiliado a StackOverflow
scroll top