¿Es necesario convertir la cadena a WideString en Delphi?
(4)
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'';
Debido a que una variable WideString
es un puntero a un WideChar
(de la misma manera que una variable AnsiString
es un puntero a un AnsiChar
.)
Y de esta manera, Delphi automáticamente "convertirá" una AnsiString en una WideString
para usted.
Actualizar
Y como ahora estamos en el mundo de UnicodeString
, lo lograrías:
interface
function StrCmpLogicalW(const sz1, sz2: UnicodeString): Integer; stdcall;
implementation
function StrCmpLogicalW; external ''shlwapi.dll'' name ''StrCmpLogicalW'';
Debido a que una variable UnicodeString
sigue siendo un puntero a una cadena terminada /0/0
de WideChars
. Así que si llamas:
var
s1, s1: AnsiString;
begin
s1 := ''Hello'';
s2 := ''world'';
nCompare := StrCmpLogicalW(s1, s2);
end;
Cuando intenta pasar un AnsiString
a una función que toma un UnicodeString
, el compilador llamará automáticamente a MultiByteToWideChar
en el código generado.
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, ordene "2" antes de "10".
Nada de esto ayuda a responder la pregunta real , que trata de cuándo se deben convertir o lanzar cadenas.
Encontré una función de API de Windows que realiza una "comparación natural" de cadenas. Se define de la siguiente manera:
int StrCmpLogicalW(
LPCWSTR psz1,
LPCWSTR psz2
);
Para usarlo en Delphi, lo declaré así:
interface
function StrCmpLogicalW(psz1, psz2: PWideChar): integer; stdcall;
implementation
function StrCmpLogicalW; external ''shlwapi.dll'' name ''StrCmpLogicalW'';
Debido a que compara las cadenas Unicode , no estoy seguro de cómo llamarlo cuando quiero comparar cadenas ANSI. Parece ser suficiente para enviar 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, por lo que esta es la razón de mi pregunta. ¿Esta función es correcta o debo convertir primero las cadenas comparadas de alguna manera?
Puede que haya una variante ANSI para su función (no he comprobado). La mayoría de las APIs anchas también están disponibles como una versión ANSI, simplemente cambie el sufijo W a una A, y listo. Windows hace 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
Tenga en cuenta que convertir una cadena en una WideString la convertirá usando la página de códigos predeterminada del sistema, que puede o no ser lo que necesita. Por lo general, desearías usar la configuración regional del usuario actual.
Desde WCharFromChar
en System.pas:
Result := MultiByteToWideChar(DefaultSystemCodePage, 0, CharSource, SrcBytes,
WCharDest, DestChars);
Puede cambiar SetMultiByteConversionCodePage llamando a SetMultiByteConversionCodePage .
Use System.StringToOleStr
, que es un envoltorio práctico alrededor de MultiByteToWideChar
, vea la 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!