Est-il nécessaire de convertir une chaîne en WideString dans Delphi?
-
06-07-2019 - |
Question
J'ai trouvé une fonction API Windows qui effectue la "comparaison naturelle". de cordes. Il est défini comme suit:
int StrCmpLogicalW(
LPCWSTR psz1,
LPCWSTR psz2
);
Pour l'utiliser dans Delphi, je l'ai déclaré ainsi:
interface
function StrCmpLogicalW(psz1, psz2: PWideChar): integer; stdcall;
implementation
function StrCmpLogicalW; external 'shlwapi.dll' name 'StrCmpLogicalW';
Comme il compare les chaînes Unicode , je ne sais pas comment l'appeler quand je vouloir comparer les chaînes ANSI. Il semble suffisant de lancer des chaînes dans WideString, puis dans PWideChar. Cependant, je ne sais pas du tout si cette approche est correcte:
function AnsiNaturalCompareText(const S1, S2: string): integer;
begin
Result := StrCmpLogicalW(PWideChar(WideString(S1)), PWideChar(WideString(S2)));
end;
Je connais très peu le codage de caractères, c’est la raison de ma question. Cette fonction est-elle correcte ou devrais-je d'abord convertir les deux chaînes comparées d'une manière ou d'une autre?
La solution
N'oubliez pas que la conversion d'une chaîne en chaîne WideString la convertira à l'aide de la page de code système par défaut, qui peut ne pas correspondre à vos besoins. En règle générale, vous souhaitez utiliser les paramètres régionaux de l'utilisateur actuel.
À partir de WCharFromChar
dans System.pas:
Result := MultiByteToWideChar(DefaultSystemCodePage, 0, CharSource, SrcBytes,
WCharDest, DestChars);
Vous pouvez modifier la valeur de DefaultSystemCodePage en appelant .
Autres conseils
Le moyen le plus simple d’accomplir cette tâche serait de déclarer votre fonction comme suit:
interface
function StrCmpLogicalW(const sz1, sz2: WideString): Integer; stdcall;
implementation
function StrCmpLogicalW; external 'shlwapi.dll' name 'StrCmpLogicalW';
Parce qu'une variable WideString
est un pointeur sur un WideChar
(de la même manière qu'une variable AnsiString
em> est un pointeur sur un AnsiChar
.)
Et ainsi, Delphi va automatiquement "convertir vers le haut". une AnsiString en WideString
pour vous.
Mettre à jour
Et puisque nous sommes maintenant dans le monde de UnicodeString
, vous le feriez:
interface
function StrCmpLogicalW(const sz1, sz2: UnicodeString): Integer; stdcall;
implementation
function StrCmpLogicalW; external 'shlwapi.dll' name 'StrCmpLogicalW';
Parce qu'une variable UnicodeString
est toujours un pointeur sur une chaîne \ 0 \ 0
terminée par WideChars
. Donc, si vous appelez:
var
s1, s1: AnsiString;
begin
s1 := 'Hello';
s2 := 'world';
nCompare := StrCmpLogicalW(s1, s2);
end;
Lorsque vous essayez de passer un AnsiString
dans une fonction prenant un UnicodeString
, le compilateur appellera automatiquement MultiByteToWideChar
pour vous dans le fichier généré. code.
CompareString prend en charge le tri numérique dans Windows 7
À partir de Windows 7, Microsoft a ajouté SORT_DIGITSASNUMBERS
dans CompareString
:
Windows 7: considérez les chiffres comme des nombres lors du tri. Par exemple, triez les mots "2". avant "10".
Rien de tout cela n'aide à répondre à la question actuelle , qui concerne le moment où vous devez convertir ou convertir des chaînes.
Il pourrait y avoir une variante ANSI pour votre fonction (je n'ai pas vérifié). La plupart des API Wide sont également disponibles en version ANSI. Il suffit de remplacer le suffixe W par un A et le jeu est défini. Dans ce cas, Windows effectue la conversion en arrière-plan de manière transparente.
PS: voici un article décrivant l'absence de StrCmpLogicalA: http://blogs.msdn.com/joshpoley/archive/2008/04/28/strcmplogicala.aspx
Utilisez System.StringToOleStr
, qui est un encapsuleur pratique autour de MultiByteToWideChar
, voir réponse 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;
Mais dans ce cas, la solution de Ian Boyd est beaucoup plus agréable!