Differences
This shows you the differences between two versions of the page.
— |
pub:labprog:2020-12-17 [2020/12/17 17:32] (current) atrent created |
||
---|---|---|---|
Line 1: | Line 1: | ||
+ | # Note lezione (17/12/2020) | ||
+ | |||
+ | testo (formattato male ma basta prendere il "grezzo", cfr. istruzioni sul wiki stesso) lezioni precedenti sul wiki del corso: http://sl-lab.it/dokuwiki/doku.php/pub:labprog:home | ||
+ | |||
+ | ## Note sulle stringhe di formato (usate ad es. in Scanf) | ||
+ | |||
+ | Prendiamo come esempio la funzione fmt.Scanf: | ||
+ | |||
+ | ```go | ||
+ | func Scanf(format string, a ...interface{}) (n int, err error) | ||
+ | |||
+ | /*Scanf scans text read from standard input, | ||
+ | storing successive space-separated values into | ||
+ | successive arguments as determined by the format [...].*/ | ||
+ | |||
+ | ``` | ||
+ | |||
+ | Il primo argomento di questa funzione è una "stringa di formato". La stringa di formato descrive esattamente quello che ci si aspetta di leggere come input (o scrivere in output, nel caso di una stampa). | ||
+ | |||
+ | |||
+ | Ad esempio, supponiamo di voler leggere una data dal linea di comando (esattamente come viene richiesto dall'esercizio 1 di oggi) nel seguente formato: `gg/mm/aaaa`. | ||
+ | |||
+ | ### Lettura corretta | ||
+ | |||
+ | ```go | ||
+ | fmt.Sscanf(os.Args[1], "%d/%d/%d", &gg, &mm, &aa) | ||
+ | fmt.Println(gg,mm,aa) | ||
+ | ``` | ||
+ | |||
+ | ```bash | ||
+ | ./main 15/09/2040 | ||
+ | 15 9 2040 # notare che lo 0 del 9 scompare | ||
+ | # leggere sez.Lunghezza e precisione in output | ||
+ | ``` | ||
+ | |||
+ | ### Spazi bianchi | ||
+ | |||
+ | Vediamo invece la seguente implementazione: | ||
+ | |||
+ | ```go | ||
+ | fmt.Sscanf(os.Args[1], "%d / %d / %d", &gg, &mm, &aa) | ||
+ | fmt.Println(gg,mm,aa) | ||
+ | ``` | ||
+ | |||
+ | La differenza rispetto a prima è che sono stati inseriti degli spazi bianchi all'interno della stringa di formato. Se alla riga di comando forniamo lo stesso input di prima, otteniamo un risultato "strambo": | ||
+ | |||
+ | ```bash | ||
+ | ./main 15/09/2040 | ||
+ | 15 0 0 | ||
+ | ``` | ||
+ | |||
+ | **Attenzione**: lo spazio bianco è un carattere, esattamente come tutti gli altri, quindi viene utilizzato come separatore. | ||
+ | |||
+ | Allora ci si potrebbe chiedere: mettendo gli *stessi* spazi bianchi anche dentro l'input, la lettura andrebbe a buon fine? *(leggi la prossima sezione)* | ||
+ | |||
+ | ### Le virgolette | ||
+ | |||
+ | ``` | ||
+ | ./main 15 / 09 / 2040 | ||
+ | 15 0 0 | ||
+ | ``` | ||
+ | |||
+ | No, nonstante l'aggiunta degli spazi, la lettura non viene effettuata correttamente. | ||
+ | |||
+ | Questo perchè gli spazi sono un separatore anche per gli argomenti a linea di comando. Infatti, se aggiungiamo i seguenti comandi al nostro programma: | ||
+ | |||
+ | ```go | ||
+ | fmt.Println("#argomenti:",len(os.Args)) | ||
+ | for pos,val := range os.Args { | ||
+ | fmt.Printf("argomento %d: %s\n", pos, val) | ||
+ | } | ||
+ | ``` | ||
+ | Otteniamo: | ||
+ | ``` | ||
+ | 15 0 0 | ||
+ | #argomenti: 6 | ||
+ | argomento 0: ./main | ||
+ | argomento 1: 15 | ||
+ | argomento 2: / | ||
+ | argomento 3: 09 | ||
+ | argomento 4: / | ||
+ | argomento 5: 2040 | ||
+ | ``` | ||
+ | |||
+ | Quindi, per poter leggere "correttamente" la data, tutti i valori dovranno essere contenuti all'interno dell'argomento #1. Per fare ciò mettiamo tra virgolette la data intera nella linea di comando (esattamente come se fosse una stringa) : | ||
+ | |||
+ | ``` | ||
+ | ./main "15 / 09 / 2040" | ||
+ | 15 9 2040 | ||
+ | #argomenti: 2 | ||
+ | argomento 0: ./main | ||
+ | argomento 1: 15 / 09 / 2040 | ||
+ | ``` | ||
+ | |||
+ | ### Utilizzare `-` come separatore | ||
+ | |||
+ | Supponiamo ora di avere come separatore il simbolo `-` al posto del simbolo `/`. | ||
+ | |||
+ | L'istruzione corretta diventa quindi: | ||
+ | |||
+ | ```go | ||
+ | fmt.Sscanf(os.Args[1], "%d-%d-%d", &gg, &mm, &aa) | ||
+ | ``` | ||
+ | |||
+ | E abbiamo come effetto: | ||
+ | |||
+ | ``` | ||
+ | ./main 15-09-2040 | ||
+ | 15 9 2040 | ||
+ | ``` | ||
+ | |||
+ | **Attenzione**: se per sbaglio fosse stato omesso il simbolo `-` all'interno della stringa di formato, si sarebbero ottenuti risultati poco piacevoli: | ||
+ | |||
+ | ```go | ||
+ | //ometto - | ||
+ | fmt.Sscanf(os.Args[1], "%d %d %d", &gg, &mm, &aa) | ||
+ | ``` | ||
+ | |||
+ | ``` | ||
+ | ./main 15-09-2040 | ||
+ | 15 0 0 | ||
+ | #argomenti: 2 | ||
+ | argomento 0: ./main | ||
+ | argomento 1: 15-09-2040 | ||
+ | ``` | ||
+ | |||
+ | Questo succede perchè il primo argomento non rispetta la stringa di formato *(infatti, il 15 viene letto, mentre tutto il resto viene scartato dal momento che ci si aspetta che ci sia lo spazio come separatore)*. | ||
+ | |||
+ | |||
+ | |||
+ | ### Tabellina specificatori | ||
+ | `%v` stampa una struct (senza nomi dei campi) | ||
+ | `%+v` stampa una struct con nomi dei campi | ||
+ | `%t` bool | ||
+ | `%d` intero | ||
+ | `%c` stampa carattere (runa) | ||
+ | `%x` valore esadecimale | ||
+ | `%f` float | ||
+ | `%s` stringa | ||
+ | |||
+ | |||
+ | ### Lunghezza e precisione in output | ||
+ | |||
+ | Formattazione output: `%[lunghezza_min][.precisione]<specificatore>` | ||
+ | |||
+ | - `lunghezza`: numero minimo di caratteri da stampare. Se il numero fornito è più corto, vengono aggiunti degli spazi bianchi **a sinstra**. Se è più lungo **non** viene tagliato. | ||
+ | |||
+ | Esempio: | ||
+ | ```go | ||
+ | //mi aspetto un numero da almeno 2 cifre | ||
+ | fmt.Printf("%2d\n", 1) | ||
+ | fmt.Printf("%2d\n", 10) | ||
+ | fmt.Printf("%2d\n", 100) | ||
+ | |||
+ | fmt.Printf("%2f\n", 1.0) | ||
+ | fmt.Printf("%2f\n", 10.0) | ||
+ | fmt.Printf("%2f\n", 100.0) | ||
+ | |||
+ | ``` | ||
+ | ```bash | ||
+ | 1 #il primo carattere è bianco | ||
+ | 10 | ||
+ | 100 | ||
+ | | ||
+ | 1.000000 #qua non accade | ||
+ | 10.000000 | ||
+ | 100.000000 | ||
+ | ``` | ||
+ | |||
+ | - `precisione` : nel caso di interi è equivalente alla lunghezza, con la differenza che al posto degli spazi bianchi vengono aggiunti degli zeri a sinistra: | ||
+ | |||
+ | ```go | ||
+ | fmt.Printf("%.3d\n", 1) | ||
+ | fmt.Printf("%2.3d\n", 1) | ||
+ | fmt.Printf("%4.3d\n", 1) | ||
+ | ``` | ||
+ | ```bash | ||
+ | 001 | ||
+ | 001 | ||
+ | 001 # non è sbagliato, lo spazio bianco a sx | ||
+ | # c'è perchè si devono stampare almeno 4 | ||
+ | # caratteri | ||
+ | ``` | ||
+ | | ||
+ | Nel caso di float, invece, indica il numero di cifre da stampare dopo la virgola | ||
+ | | ||
+ | ```go | ||
+ | fmt.Printf("%2.0f\n", 10.42) | ||
+ | fmt.Printf("%2.1f\n", 10.42) | ||
+ | fmt.Printf("%2.3f\n", 10.42) | ||
+ | ``` | ||
+ | | ||
+ | ``` | ||
+ | 10 | ||
+ | 10.4 | ||
+ | 10.420 | ||
+ | ``` | ||
+ | |||
+ | --- | ||
+ | | ||
+ | Tornando velocemente all'esempio della data, eravamo rimasti con: | ||
+ | | ||
+ | ```go | ||
+ | fmt.Sscanf(os.Args[1], "%d/%d/%d", &gg, &mm, &aa) | ||
+ | fmt.Println(gg,mm,aa) | ||
+ | ``` | ||
+ | |||
+ | ```bash | ||
+ | ./main 15/09/2040 | ||
+ | 15 9 2040 | ||
+ | ``` | ||
+ | Se al posto di `9` volessimo stampare `09`, dovremmo modificare il codice come segue: | ||
+ | |||
+ | ```go | ||
+ | fmt.Printf("%.2d %.2d %d\n", gg, mm , aa) | ||
+ | ``` | ||
+ | ``` | ||
+ | ./main 15/09/2040 | ||
+ | 15 09 2040 | ||
+ | ``` | ||
+ | |||
+ | |||
+ | |||
+ | |||
+ | |||
+ | . | ||
+ | |||
+ | |||
+ | |||
+ | |||