Domanda

Ho un semplice tstringlist. Faccio un tstringlist.sort su di esso.

Quindi noto che il sottolineatura "_" ordina prima della lettera maiuscola "A". Ciò era in contrasto con un pacchetto di terze parti che stava ordinando lo stesso testo e ordinato _ dopo A.

Secondo il set di caratteri ANSI, AZ sono i personaggi 65 - 90 e _ sono 95. Quindi sembra che il pacchetto di terze parti stia usando quell'ordine e tstringlist.sort non lo è.

Ho perforato le viscere di TstringList.sort e sta ordinando usando AnsicomParestr (Case Sensibile) o AnsicomPareText (Case Insensitive). L'ho provato in entrambi i modi, impostando il valore di sensibilizzazione della mia stringlist su true e poi falso. Ma in entrambi i casi, prima la specie di "_".

Non riesco proprio a immaginare che questo sia un bug in Tstringlist. Quindi ci deve essere qualcos'altro qui che non vedo. Cosa potrebbe essere?

Quello che devo davvero sapere è come posso far ordinare la mia lista di tstring in modo che sia nello stesso ordine dell'altro pacchetto.

Per riferimento, sto usando Delphi 2009 e sto usando le stringhe Unicode nel mio programma.


Quindi la risposta finale qui è quella di sovrascrivere l'ANSI paragona a quello che vuoi (ad es. Confronto non-ansi) come segue:

type
  TMyStringList = class(TStringList)
  protected
    function CompareStrings(const S1, S2: string): Integer; override;
  end;

function TMyStringList.CompareStrings(const S1, S2: string): Integer;
begin
  if CaseSensitive then
    Result := CompareStr(S1, S2)
  else
    Result := CompareText(S1, S2);
end;
È stato utile?

Soluzione

Definire "correttamente".
i18n L'ordinamento dipende totalmente dal tuo locale.
Quindi sono totalmente d'accordo con PAPÀ che questo non è un bug: il valore predefinito Ordinare Il comportamento funziona come progettato per consentire a I18N di funzionare correttamente.

Piace Gerry menziona, Tstringlist.sort usi Ansicomparestr e AnsicomPareText (Spiegherò in poche righe come lo fa).

Ma: TstringList è flessibile, contiene Ordinare, Customsort e Confronti, che sono tutti virtuali (quindi puoi prevalerli in una classe discendente)
Inoltre, quando chiami Customsort, puoi collegare il tuo Confrontare funzione.

Al di questa risposta è un Confrontare funzione che fa quello che vuoi:

  • Maiuscole e minuscole
  • Non usando alcun locale
  • Basta confrontare il valore ordinale dei caratteri delle stringhe

Customsort è definito come questo:

procedure TStringList.CustomSort(Compare: TStringListSortCompare);
begin
  if not Sorted and (FCount > 1) then
  begin
    Changing;
    QuickSort(0, FCount - 1, Compare);
    Changed;
  end;
end;

Per impostazione predefinita, il Ordinare Il metodo ha un'implementazione molto semplice, passando un valore predefinito Confrontare funzione chiamata StringListComparestrings:

procedure TStringList.Sort;
begin
  CustomSort(StringListCompareStrings);
end;

Quindi, se definisci il tuo TstringListsortCompare compatibile Confrontare Metodo, quindi puoi definire il tuo smistamento.
TstringListsortCompare è definito come una funzione globale che prendono TstringList e due indici che riferiscono gli elementi che si desidera confrontare:

type
  TStringListSortCompare = function(List: TStringList; Index1, Index2: Integer): Integer;

Puoi usare il StringListComparestrings Come linea guida per l'implementazione del tuo:

function StringListCompareStrings(List: TStringList; Index1, Index2: Integer): Integer;
begin
  Result := List.CompareStrings(List.FList^[Index1].FString,
                                List.FList^[Index2].FString);
end;

Quindi, per impostazione predefinita tstringlist.sort difer a tlist.comparestrings:

function TStringList.CompareStrings(const S1, S2: string): Integer;
begin
  if CaseSensitive then
    Result := AnsiCompareStr(S1, S2)
  else
    Result := AnsiCompareText(S1, S2);
end;

Che quindi usano la funzione API di Windows Under liscia Confronto con la locale utente predefinita Locale_user_default:

function AnsiCompareStr(const S1, S2: string): Integer;
begin
  Result := CompareString(LOCALE_USER_DEFAULT, 0, PChar(S1), Length(S1),
    PChar(S2), Length(S2)) - 2;
end;

function AnsiCompareText(const S1, S2: string): Integer;
begin
  Result := CompareString(LOCALE_USER_DEFAULT, NORM_IGNORECASE, PChar(S1),
    Length(S1), PChar(S2), Length(S2)) - 2;
end;

Finalmente il Confrontare funzione di cui hai bisogno. Ancora una volta i limiti:

  • Maiuscole e minuscole
  • Non usando alcun locale
  • Basta confrontare il valore ordinale dei caratteri delle stringhe

Questo è il codice:

function StringListCompareStringsByOrdinalCharacterValue(List: TStringList; Index1, Index2: Integer): Integer;
var
  First: string;
  Second: string;
begin
  First := List[Index1];
  Second := List[Index2];
  if List.CaseSensitive then
    Result := CompareStr(First, Second)
  else
    Result := CompareText(First, Second);
end;

Delphi non è chiuso, al contrario: spesso è un'architettura davvero flessibile.
Spesso è solo un po 'di scavo per vedere dove puoi agganciarsi a quella flessibilità.

--jeroen

Altri suggerimenti

AnsicomParestr / AnsicomPareText tiene conto di più del numero di carattere. Prendono in considerazione il locale per gli utenti, quindi "e" ordinerà insieme a "é", "ê" ecc.

Per farlo ordinarlo in ordine ASCII, utilizzare una funzione di confronto personalizzata Come descritto qui

Cattura dei risultati da una sotto-espressione ripetuta (nel tuo caso (([A-Za-z]*)(\s|-)){1,3}) diventa difficile in qualsiasi lingua.Suggerisco quanto segue come un approccio più semplice:

1) Abbina l'intera porzione che ti interessa con un semplice regex:

GetDelay.Pattern = "is sadly currently in (.*?) undetermined"
.

2) Una volta che hai abbinato la porzione di interesse, eseguire ulteriori analisi per ottenere ciò che desideri.Potresti usare un altro regex per questo passaggio, anche se penso che potresti solo Split() con uno spazio del delimitatore.

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