Skip to content
Snippets Groups Projects
Commit cb7255fc authored by Anna Morpurgo's avatar Anna Morpurgo
Browse files

note sulla gestione dell'input

parent 16f7360f
Branches main
No related tags found
No related merge requests found
# Lettura e gestione dell'input
## Package per la lettura
I seguenti package contengono funzioni e metodi per gestire l'input:
- package fmt
- package bufio
- package strings
- package ioutil
## L'input può provenire da
- standard input (tastiera o file ridiretto)
```
$ ./myProgram1
sto inviando dati da tastiera
$ ./myProgram1 < myInputFile
```
*Nel secondo caso lancio lo stesso identico programma (myProgram1.go), ma (come utente) uso il file myInputFile invece della tastiera per fornire l'input.*
- linea di comando (salvato automaticamente in `os.Args`)
```
$ ./myProgram2 scrivo qui i dati per il programma
```
*In questo caso, ogni volta che viene eseguito il programma, tutte le parole che seguono il nome del programma vengono salvate automaticamente nella slice os.Args a partire da os.Args[1].*
*Quindi in questo esempio specifico in os.Args[1] viene salvata la stringa "scrivo", in os.Args[2] "qui", in os.Args[3] "i", ..., in os.Args[7] "programma".*
*Nota: in os.Args[0] viene salvato il nome dell'eseguibile (./myProgram2).*
- file
```
$ ./myProgram3 myInputFile
```
*In questo caso il programma myProgram3.go, una volta lanciata l'esecuzione, si troverà (automaticamente) in os.Args[1] il nome del file ("myInputFile"), che potrà aprire (e chiudere) e leggere (vedi più avanti come).*
**Ricordarsi di fare sempre i controlli per evitare panic!**
---
**Nota di terminologia**. Useremo il termine *stringa* per denotare una qualsiasi sequenza di caratteri, che può quindi contenere anche spazi bianchi, tab, ecc., e invece con il termine "parola" una sequenza di caratteri senza spazi bianchi, tipicamente delimitata da essi. Ad esempio:\
"Sempre caro mi fu quest’ermo colle, e questa siepe," è una stringa.\
Le parole in essa contentute sono:\
"Sempre", "caro", "mi", "fu", "quest'ermo", "colle,", "e", "questa", "siepe,".
## fmt.Scan vs bufio.Scanner
### fmt.Scan
Per leggere **da standard input un dato o una lista di dati separati da spazi bianchi** (non importa quanti spazi e non importa di che tipo, se ' ', '\n\', '\t', ...), la soluzione più semplice è:\
`fmt.Scan(&var_1, &var_2, ..., &var_n)`
Ad esempio:
```go
var nome, cognome string
var altezza int
var peso float64
fmt.Scan(&nome, &cognome, &altezza, &peso)
```
### bufio.Scanner su os.Stdin
Per leggere **da standard input righe di un testo**, si usa Scanner di bufio. Tipicamente:
```go
myScanner := bufio.NewScanner(os.Stdin)
for myScanner.Scan() {
line := myScanner.Text()
....
}
```
Se la riga è una sola:
```go
myScanner := bufio.NewScanner(os.Stdin)
myScanner.Scan() {
line := myScanner.Text()
....
```
---
### bufio.Scanner su file
Per leggere **righe di un testo da file** anche si usa Scanner di bufio, come sopra, con in più l'apertura e la chiusura del file:
```go
var fileName string
...
myFile, err := os.Open(fileName)
if err != nil {
fmt.Println("file not found")
return
}
defer myFile.Close()
myScanner := bufio.NewScanner(myFile)
for myScanner.Scan() {
line := myScanner.Text()
....
}
```
### bufio.Scanner con "passo" più piccolo
Per leggere **procedendo per byte, rune o parole** invece che per righe, si usa il metodo Split(bufio.ScanXxx), che modifica appunto il modo di procedere di Scan().
Anche procedendo per byte o rune, si ottengono sempre stringhe, in questi casi di 1 solo carattere.
```go
...
myScanner := bufio.NewScanner(myFile)
myScanner.Split(bufio.ScanWords) //o ScanBytes o ScanRunes
for myScanner.Scan() {
word := myScanner.Text() //Sto leggendo parola per parola
....
}
```
```go
...
myScanner := bufio.NewScanner(myFile)
myScanner.Split(bufio.ScanRunes) //Ora voglio leggere runa per runa
for myScanner.Scan() {
oneRuneString := myScanner.Text(). //Anche in questo caso Text() restituisce una stringa, di sola runa
....
}
```
### Funzioni di libreria per spezzare l'input
**In alternativa a Split(bufio.ScanWords)**, il package `strings` mette a disposizione:
```go
strings.Fields(s string)
```
che restituisce una slice di stringhe che contiene le parole di `s`, cioè le sottostringhe identificate da spazi bianchi.
Ricordatevi sempre anche del vecchio fmt.Scan, che risolve molte situazioni in modo semplice.
---
# Pre-elaborazione / estrazione di dati
### Estrazione di elementi singoli da un contesto, come cifre da un numero o caratteri da una stringa
- cifre da un numero n
- se è stato salvato come int, con un ciclo
```go
for n > 0 {
cifra := n%10
n /= 10
}
```
- se è stato salvato come stringa, con ciclo
```go
for i := 0; i < len(s); i++ {
cifra := n[i]
}
```
- caratteri da una stringa s
- se byte, con ciclo di conteggio
```go
for i := 0; i < len(s); i++ {
cifra := s[i]
}
```
- se rune, con un for range
```go
for _, cifra := range s {
...
}
```
- o con un ciclo di conteggio
```go
slice := []rune(s)
for i := 0; i < len(slice); i++ {
cifra := slice[i]
}
```
---
### Estrazione di dati da una stringa formattata
Ad esempio, una data gg/mm/aaaa
Per quando le righe o le stringhe in input che hanno un **formato fissato**,
- se c'è un solo tipo di separatore:
- strings.Split(s, sep string)
- Esempio:
```go
sep := "/"
slice := strings.Split(s, sep)
```
- se ci sono diversi separatori, il package `fmt` mette a disposizione la funzione `Scanf`, che usa una sintassi analoga a `Printf` per leggere e memorizzare valori (invece di stamparli):
```go
fmt.Scanf(format string, lista di puntatori a var)
```
Ad esempio
```go
var ore, min, sec int
//stampo orario in formato h:m:s
fmt.Prinf("%d:%d:%d", ore, min, sec)
//leggo orario (da tastiera), con i valori
//di ore, min e sec in una stringa in formato h:m:s
fmt.Scanf("%d:%d:%d", &ore, &min, &sec)
```
E anche Sscanf per estrarre dati da una stringa
- Esempio:
```go
stringData := "15/12/2022"
fmt.Sscanf(stringData, "%d/%d/%d", &gg, &mm, &aa)
```
**Nota**.
`%s` prende tutti i caratteri fino al primo carattere di spaziatuta o fino alla fine dell'input, se non ci sono spaziature. In alternativa si può specificare il numero (massimo) di caratteri da leggere (se non si incontra prima un carattere di spaziatura):
`%5s` legge una stringa di (max) 5 caratteri (caratteri di spaziatura esclusi).\
Ad esempio,
```go
fmt.Sscanf(" 1234567 ", "%5s%d", &s, &i)
```
memorizzerà "12345" in s e 67 in i.
```go
Sscanf(" 12 34 567 ", "%5s%d", &s, &i)
```
memorizzerà "12" in s e 34 in i.
```go
var ore, min, sec int
var pre string
//leggo orario (da tastiera), con i valori
//di ore, min e sec in una stringa in formato "UTC h:m:s"
ora := "UTC-11:36:21"
fmt.Sscanf(ora, "%4s%d:%d:%d", &pre, &ore, &min, &sec)
```
memorizzerà "UTC-" in pre, 11 in ore, 36 in min e 21 in sec.
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Please register or to comment