Dart



Dati: le stringhe          

In questo linguaggio, come in innumerevoli altri, le stringhe sono sequenze immutabili di caratteri UTF16. Questo tipo di conformazione garantisce la compatibilità con Javascript e con tutti i browsers esistenti, come è specificato nel draft originale di Google. L'immutabilità di una stringa sta a significare che qualunque operazione sia compiuta su di essa non la modifica ma in realtà ne crea una nuova modificata. Le stringhe possono essere delimitate da una coppia di doppi apici o da una coppia di singoli apici. Esse inoltre possono essere espanse su riga singola e su più righe. Le stringhe delimitate un doppio apice possono contenere stringhe delimitate da coppie di singoli apici e viceversa. Vediamo alcuni esempi:

String s1 = "ciao";
String s2 = 'mondo';
String s3 = "ciao 'mondo'";
String s4 = 'ciao "mondo"';


Le stringhe multilinea possono essere delimitate ancora da singoli apici o doppi apici ma questi devono essere, all'inizio e alla fine, in numero di 3:

String s1 = '''ciao
mondo''';
String s2 = """hello
world""";


Anche in Dart sono previsti i soliti caratteri di escape, quelli tipici di ogni linguaggio di programmazione, che possono essere inseriti sia nelle stringhe delimitate da doppi apici che in quelle circondate dai singoli apici.

String s1 = "ciao\nmondo";
print(s1);
String s2 = 'ciao\tmondo';
print(s2);


Bel primo esempio abbiamo un carattere di newline, nel secondo una tabulazione orizzontale. On line potrete facilmente trovare tabelle complete.
Dart prevede anche le raw string, all'interno delle quali i caratteri escape sono uguali agli altri e non provvedono alcuna formattazione, che sono introdotte dal prefisso "r" prima degli apici che, anche in questo caso, possono essere quelli doppi o quelli singoli:

String s1 = r"ciao\nmondo";
String s2 = r'ciao\tmondo';

Abbiamo detto all'inizio che le stringhe in Dart sono sequenze. Ebbene ogni elemento all'interno di queste sequenze è caratterizzato da un indice intero che ne individua, sequenzialmente, la posizione all'interno della stringa stessa. Le stringhe in Dart sono 0-based ovvero l'indice del primo carattere a sinistra è 0 l'ultimo avrà indice n-1 ove n è il numero complessivo di caratteri.

  Esempio 3-1
1
2
3
4
5
main() {
String s1 = "abcdef";
print(s1[0]);
print(s1[6]); // attenzione!
}

La riga 3 espone a video il carattere 'a' mentre la 4 genera un errore perchè siamo andati oltre gli indici consentiti (che vanno da 0 a 5). Come è evidente, in modo molto simile ad altri linguaggi, il singolo carattere viene individuato per mezzo dell'operatore [n] dove n indica una locazione nel range valido per la stringa

La creazione di una stringa, come abbiamo visto in tutti gli esempi precedenti, è immediata. Tuttavia è anche possibile che non si conosca in fase di scrittura del codice quale sarà l'esatto contenuto di una stringa, ad esempio quando questa viene generata in funzione di una certa interazione con l'utente. Ecco quindi che possiamo costruire una stringa a runtime e ciò avviene grazie alla classe StringBuffer nel modo seguente:

var str01 = StringBuffer(); // creiamo uno stringbuffer vuoto
str01.write("aa"); // aggiungiamo ad esso l'elemento "aa"
str01.write("bb"); // aggiungiamo un altro elemento, "bb"
str01.writeAll(['cc', 'dd', 'ee'], 'XX'); // usiamo writeAll che permette di unire gli elementi di un iterable inserendo un divisore, in questo caso XX
var str02 = str01.toString(); // attraverso toString lo StringBuffer viene finalmente riversato in formato stringa
A questo punto str02 è la stringa: aabbccXXddXXee

Un metodo alternativo lo si ritrova parlando degli array e degli iterable in genere.

Abbiamo già visto nel capitolo introduttivo l'interpolazione che avviene tramite il simbolo $ e rimando a quel paragrafo per visionare un esempio.

E veniamo alle operazioni più tipiche che è possibile fare su questa tipologia di dati; la prima è la concatenazione che abbiamo già visto anche in questo caso nel capitolo introduttivo e che possiamo fare anche usando l'operatore + o, come avevamo detto, tramite affiancamento delle stringhe stesse.

String s1 = "aaa";
String s2 = "bbb";
print(s1 + s2);
print("aaa" "bbb");


L'output è sempre lo stesso:

aaabbb
aaabbb

nel secondo caso non si può scrivere print(s1 s2) perchè print accetta un solo parametro. Comunque va bene per dimostrare l'assunto; tendenzialmente prediligo la prima forma perchè esplicita l'operazione in modo secondo me più chiaro, insomma si capisce bene cosa si sta facendo, ma è una mia preferenza personale.

La lunghezza di una stringa è indicata dalla proprietà length:

print("ciao.length);

Effettuare ricerche di varia natura in una stringa è decisamente semplice grazie al metodo contains:

String s1 = "abcdef";
print(s1.contains("bsc"));
print(s1.contains('ab'));


la seconda riga restituisce false, la terza true. Anche in questo caso è indifferente usare gli apici o i doppi apici. Un metodo alternativo è usare indexOf che restituisce anche l'indce esatto della stringa cercata all'interna di quella che la contiene; se non la stringa cercata non viene trovata il risultato restituito è -1, cosa questa che permette facilmente di usare indexOf in alternativa a contains (che però restituisce un booleano il che può garantire una maggior efficienza).

print(s1.indexOf("bc"));

questa istruzione, riferita alla stringa s1 del frammento precedente, stampa a video il numero 1, che è l'indice al quale inizia la sottostringa "bc".
Istruzioni analoghe sono startsWith e endsWith che indicano se la stringa inizia o finisce con una certa sottostringa. Sono più efficienti, in quanto mirate, per quei casi specifici.

La possibilità di lavorare su indici facilita l'estrazione di sottostringhe tramite substring(indice di partenza, indice finale):

String s1 = "abcdef";
print(s1.substring(2,5));


Output:

cde

Altra istruzione utile è split che, specificato un separatore, crea un array nel quale ogni elemento è una parte della stringa.

  Esempio 3.2
1
2
3
4
5
main() {
String s1 = "Ciao a tutto il mondo";
var v1 = s1.split(' ');
print(v1[2]);
}

Il separatore è lo spazio e quindi la riga 3 crea un array (caso mai guardate l'apposito paragrafo) composto da 4 elementi:
"Ciao", "a", "tutto", "il", "mondo". Indicizzato anch'esso da 0 a n-1, ove n è il numero degli elementi, per cui l'output sarà:

tutto

Per convertire una tringa in caratteri maiuscoli o minuscoli sono disponibili toLowerCase() e toUpperCase().

String s1 = "aBcDeF";
print(s1.toLowerCase());
print(s1.toUpperCase());


Infine segnalo trim che elimina gli spazi iniziali di una stringa:

"   aaa".trim() -> "aaa"