Delphi

AnsiIndexStr: simulare un case su stringhe in Object Pascal

calendar_today personTeam EGSOFT schedule3 min di lettura
info

Disclaimer: le informazioni pubblicate in questa sezione hanno finalità di pura divulgazione tecnica. EG Software S.r.l. non si assume alcuna responsabilità per un utilizzo improprio dei contenuti, né per eventuali danni diretti o indiretti derivanti dalla loro applicazione, e non garantisce l'aggiornamento, l'accuratezza o la completezza delle informazioni riportate. Prima di utilizzare in produzione codice o procedure qui descritte, verificane sempre l'adeguatezza al proprio contesto.

Il costrutto case di Object Pascal funziona solo su tipi ordinali (interi, caratteri, enumerazioni): non accetta direttamente una string. Il risultato è che confrontare una stringa con più valori possibili finisce spesso in una catena di if..else if, meno leggibile e più scomoda da estendere di un vero case. System.StrUtils offre un modo elegante per aggirare il problema.

Il problema: una catena di if

Il codice che si vuole evitare è questo, ripetuto magari per una decina di valori possibili:

if Tipo = 'E' then
  Result := 'Entrata'
else if Tipo = 'U' then
  Result := 'Uscita'
else if Tipo = 'R' then
  Result := 'Rimborso'
else
  Result := 'Sconosciuto';

La soluzione: AnsiIndexStr

AnsiIndexStr(const AText: string; const AValues: array of string): Integer restituisce la posizione (0-based) di AText all'interno dell'array AValues, oppure -1 se non trova corrispondenza. Passando quel risultato a un case, si ottiene l'equivalente di uno switch su stringhe:

uses
  System.StrUtils;

function TipoRigaEsteso(const Tipo: string): string;
begin
  case AnsiIndexStr(Tipo, ['E', 'U', 'R']) of
    0: Result := 'Entrata';
    1: Result := 'Uscita';
    2: Result := 'Rimborso';
  else
    Result := 'Sconosciuto'; // AnsiIndexStr ha restituito -1: nessuna corrispondenza
  end;
end;

Il confronto è case-sensitive e usa la codifica locale ("Ansi", nel nome storico della funzione): 'e' minuscolo non corrisponderebbe a 'E'. Se serve un confronto insensibile a maiuscole/minuscole, la variante da usare è AnsiIndexText, con la stessa identica firma.

Perché è meglio della catena di if

Il vantaggio non è solo estetico. Con l'array esplicito, aggiungere un nuovo valore da riconoscere significa aggiungere una voce all'array AValues e un nuovo ramo al case, in due punti vicini e paralleli: è più difficile dimenticare di gestire un caso, cosa che invece capita più facilmente in una catena di if..else if lunga, dove un nuovo ramo va inserito nel posto giusto tra gli altri.

Quando basta un booleano: MatchStr

Se l'obiettivo non è ramificare su più valori ma solo verificare se una stringa corrisponde a uno tra diversi valori ammessi (senza bisogno di sapere quale), MatchStr — sempre in System.StrUtils — è più diretta di un AnsiIndexStr(...) >= 0:

if MatchStr(Tipo, ['E', 'U', 'R']) then
  // Tipo è uno dei tre valori ammessi
else
  // Tipo non è riconosciuto

Tra le due, la scelta dipende da cosa serve dopo il controllo: AnsiIndexStr quando il codice successivo deve comportarsi diversamente per ciascun valore, MatchStr quando basta sapere sì/no se il valore è tra quelli ammessi.

Altri articoli su Delphi grid_viewTutte le tematiche
Scrivici su WhatsApp