¿Es necesario convertir una cadena a WideString en Delphi?
-
06-07-2019 - |
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?
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);
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!