Domanda

Ho trovato una funzione API di Windows che esegue il "confronto naturale" di stringhe. È definito come segue:

int StrCmpLogicalW(
    LPCWSTR psz1,
    LPCWSTR psz2
);

Per usarlo in Delphi, l'ho dichiarato in questo modo:

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

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

Poiché confronta le stringhe Unicode , non sono sicuro di come chiamarlo quando vuoi confrontare le stringhe ANSI. Sembra essere abbastanza per lanciare stringhe su WideString e poi su PWideChar, tuttavia, non ho idea se questo approccio sia corretto:

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

So molto poco sulla codifica dei caratteri, quindi questa è la ragione della mia domanda. Questa funzione è OK o devo prima convertire entrambe le stringhe confrontate in qualche modo?

È stato utile?

Soluzione

Tieni presente che il cast di una stringa in WideString la convertirà utilizzando la tabella codici di sistema predefinita che potrebbe essere o meno ciò di cui hai bisogno. In genere, si desidera utilizzare le impostazioni internazionali dell'utente corrente.

Da WCharFromChar in System.pas:

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

È possibile modificare DefaultSystemCodePage chiamando .

Altri suggerimenti

Il modo più semplice per eseguire l'attività sarebbe dichiarare la tua funzione come:

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

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

Poiché una variabile WideString è un puntatore a una WideChar (allo stesso modo una variabile AnsiString < em> è un puntatore a un AnsiChar .)

E in questo modo Delphi automaticamente "quot-up-convert" " un AnsiString per un WideString per te.

Aggiornamento

E poiché ora siamo nel mondo di UnicodeString , dovresti farcela:

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

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

Perché una variabile UnicodeString è ancora un puntatore a una stringa terminata \ 0 \ 0 di WideChars . Quindi se chiami:

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

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

Quando provi a passare un AnsiString in una funzione che accetta un UnicodeString , il compilatore chiamerà automaticamente MultiByteToWideChar per te nel generato codice.

CompareString supporta l'ordinamento numerico in Windows 7

A partire da Windows 7, Microsoft ha aggiunto SORT_DIGITSASNUMBERS a CompareString :

  

Windows 7: considera le cifre come numeri durante l'ordinamento, ad esempio ordina " 2 " prima di "10".

Niente di tutto ciò aiuta a rispondere alla effettiva domanda, che riguarda quando devi convertire o lanciare stringhe.

Potrebbe esserci una variante ANSI per la tua funzione (non ho verificato). La maggior parte delle API Wide sono disponibili anche come versione ANSI, basta cambiare il suffisso W in una A e il gioco è fatto. In questo caso Windows esegue la conversione avanti e indietro in modo trasparente per te.

PS: ecco un articolo che descrive la mancanza di StrCmpLogicalA: http://blogs.msdn.com/joshpoley/archive/2008/04/28/strcmplogicala.aspx

Usa System.StringToOleStr , che è un utile wrapper per MultiByteToWideChar , vedi Risposta di 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;

Ma poi, La soluzione di Ian Boyd sembra ed è molto più bella!

Autorizzato sotto: CC-BY-SA insieme a attribuzione
Non affiliato a StackOverflow
scroll top