Kotlin Language

Le stringhe

Parliamo ora di un costrutto di enorme importanza in Kotlin come in ogni altro linguaggio. Le stringhe, come noto, si presentano come una sequenza finita di caratteri alfanumerici. Le stringhe sono immutabili, il che significa che ogni eventuale variazione effettuata su di essa in realtà crea un'altra stringa che riporta le modifiche. Il tipo, all'interno del linguaggio, è identificato dalla keyword String. e possiamo trovare due tipologie di stringhe:
  • stringhe con caratteri di escape
  • raw string

Le prime sono stringhe abbastanza comuni nel campo della programazione, sono comprese all'interno di una coppia di doppi apici e possono contenere sequenze di escape:

"Ciao, Mondo\nCiao Universo"

produce in pratica

Ciao Mondo
Ciao Universo

Una raw string invece è delimitata da una coppia di tripli apici e può contenere qualsiasi carattere, non ci saranno formattazioni di alcun tipo nel risultato:

"""Ciao, Mondo\nCiao Universo""" produce in pratica

Ciao Mondo\nCiao Universo

I caratteri di escape sono quelli comuni alla maggior parte dei linguaggi di programmazione, personalmente non conosco eccezioni, esoterici a parte,

Sequenza escape

Rappresentazione

\a

Bell (alert)

\b

Backspace

\f

Formfeed

\n

A capo

\r

Ritorno del carrello

\t

Tabulazione orizzontale

\v

Tabulazione verticale

\'

Singolo apice

\"

Doppio apice

\\

Backslash

\?

Punto interrogativo

\ooo

Carattere ASCII - rappresentazione ottale

\xhh

Carattere ASCII - rappresentazione esadecimale

\xhhhh

Carattere Unicode con rappresentazione esadecimale estesa

Come detto, le stringhe sono delle sequenze di caratteri. Esse sono ordinate e indicizzate. L'indice del primo elemento di una stringa 0 e l'accesso può avvenire tramite l'operatore
[]. L'indicizzazione è ottenuta tramite numeri interi in sequenza aritmetica. Pertanto l'ultimo indice di una stringa è uguale al numero di elementi in essa pèresenti meno 1. Vediamo ora un esempio completo in cui vedremo come dichiarare le stringhe facendone un primo uso di base:

  Esempio 6.1
1
2
3
4
5
6
fun main(args: Array<String>)
{
  val s1 = "abcde"
  println(s1[0])
  println(s1[2])
}

Abbiamo scritto una semplice scritta estraendone poi, come vi sarù facile verificare, i caratteri 'a' e 'c' che si trovano agli indici 0 e 2 rispettivamente. Per quanto detto prima quindi la situazione è la seguente:

Elementi della stringa a b c d e
Indici 0 1 2 3 4

Come evidenziato nel primo capitolo ricordiamoci la possibilità di intepolare le stringhe con le variabili, abbiamo visto che per fare ciò dobbiamo ricorrere all'operatore $.

Un caso che capita sovente è quello di iterare sui singoli elementi. La cosa è molto semplice:

var s1 = "abcdefghi"
s1.forEach { x -> println(x) }


oppure, più banalmente:

var s1 = "abcdefghi"
for (x in s1)
{
  println(x)
}

Lavorare con le stringhe è pratica del tutto comune ovviamente e se conoscete già un altro linguaggio di programmazione in Kotlin non troverete grosse novità. Vediamo alcune operazioni di uso comune e gli strumenti che abbiamo a disposizione. La più banale delle proprietà, e anche l'unica, tuttavia utilissima, è

length -  restituisce la lunghezza della stringa, ovvero il numero di caratteri che la compongono. Nell'esempio precedente possiamo aggiungere la riga:
println(s1.length)
che stampa a video il numero 5, dal momento che s1 contiene 5 elementi.

Tra i numerosi metodi segnalo invece:

count - analogo a length, restituisce il numero di elementi della stringa
s1.count()

get - che restituisce l'elemento ad un dato indice, similmente a quanto fa l'operatore
[]
println(s1.get(3))

plus - interessante proprietà che contatena la stringa con la rappresentazione in stringa di un altro oggetto di qualsiasi tipo. Sempre restando all'esempio precedente, se scriviamo:
println(s1.plus(334)) abbiamo come output
abcde334
in quanto 334, che è un intero, viene convertito in stringa e poi concatenato.

subSequence - origina una nuova sequenza di caratteri creata specificando un intervallo di indici in una stringa di partenza. La sintassi è:
stringabase.subSequence(indice di partenza, indice finale)
tenendo presente che la nuova stringa termina al carattere precedente quello indicato dall'indice finale. Quindi, sempre prendendo come base il programma 6.1 possiamo scrivere:

val s2 = s1.subSequence(2,4)
println(s2)


che dà come output:

cd

ovvero i caratteri 2 e 3 (il 4, come detto, è escluso)

Per concatenare due o più stringhe ci sono più opzioni. Una, come è facile capire, può far uso di plus, vista in precedenza, che funziona solo con due stringhe. Oppure, in maniera più grossolana, potete ricorrere al classico +, un po' così ma fa il suo lavoro. Il metodo più elegante è fare uso del $.

val s1 = "abcde"
val s2 = "fghi"
val s3 = "$s1$s2"
val s4 = s1 + s2


la terza e la quarta riga ci indicano i due metodi, equivalenti nel risultato finale.

Per trovare un elemento all'interno di una stringa potete operare in vari modi, il più semplice è usare indexof che restituisce l'indice dell'elemento cercato oppure -1 se non c'è.

val s1 = "abcde"
println(s1.indexOf('b'))
println(s1.indexOf('r'))


restituisce gli indici 1, che è quello del carattere 'b' e -1 in quanto 'r' non è presente nella stringa.
Se invece volete trovare una sottostringa in una stringa è comodo utilizzare contains che restituisce true o false a seconda naturalmente che trovi oppure no riscontro:

val s1 = "abcdefghi"
println(s1.contains("bcd"))


In questo caso abbiamo come risultato true.

Se invece volete estrarre una sottostringa da una stringa ecco substring (simile a subSequence, ma in questo caso viene genrata una stringa vera e propria) nei suoi due formati:

substring(indice di partenza) che estrae una sottostringa a partire dall'indice specificato fino alla fine
substring(indice di partenza, indice finale) che estrae la sottostringa compresa tra l'indice di partenza e quello finale meno 1.

val s1 = "abcdefghi"
println(s1.substring(3))
println(s1.substring(2,5))

fornisce due output diversi:

defghi
cde


Cancellare gli elementi di una stringa è banale grazie a drop e dropLast

drop(n) cancella n interi partendo dall'inizio della stringa
dropLast(n) cancella n interi partendo dal fondo

Eccovi un piccolo programma completo:

  Esempio 6.2
1
2
3
4
5
6
7
8
9
10
fun main(args: Array<String>)
{
  var s1 = "abcdefghi"
  println(s1.dropLast(3))
  println(s1.drop(3))
  println(s1)
  s1 = s1.drop(s1.length)
  println(s1)
  println(s1.length)
}

Il trucco per ripulire la stringa è quello di effettuare su di essa un drop per tutta la sua lunghezza (si può fare, naturalmente, anche usando dropLast). Noterete che la stringa s1 è denotata con var, altrimenti non sarebbe possibile eliminare nulla su di essa. 

isEmpty - ci dice se una stringa è vuota
isBlank - ci dice se una stringa è vuota oppure contiene solo dei blank.

entrambi restituiscono true o false. Corrispondentemente, esistono anche isNotEmpty e isNotBlank.


Bene, questa è solo una rapida carrellata dei numerosissimi metodi che avete a disposizione in questo potente linguaggio, carrellata che dovrebbe mettervi in condizione di lavorare in modo basilare ma abbastanza interessante con le stringhe. Una panoramica esaustiva di tutto quel che avete a disposizione, c'è veramente parecchio materiale utile, la potete trovare qui.