2010-03-10 16 views
6

Sto cercando l'equivalente Go di scanf(). Ho provato con seguente codice:Cercare l'equivalente di scanf

1 package main 
    2 
    3 import (
    4  "scanner" 
    5  "os" 
    6  "fmt" 
    7) 
    8 
    9 func main() { 
10  var s scanner.Scanner 
11  s.Init(os.Stdin) 
12  s.Mode = scanner.ScanInts 
13  tok := s.Scan() 
14  for tok != scanner.EOF { 
15   fmt.Printf("%d ", tok) 
16   tok = s.Scan() 
17  } 
18  fmt.Println() 
19 } 

lo eseguo con il contributo di un testo con una linea di numeri interi. Ma emette sempre -3 -3 ...

E come scansionare una linea composta da una stringa e alcuni interi? Cambiare la modalità ogni volta che si incontra un nuovo tipo di dati?

la documentazione del pacchetto:

scanner pacchetto

Uno scanner general-purpose per UTF-8 testo codificato.

Ma sembra che lo scanner non è per uso generale.

codice aggiornato:

func main() { 
    n := scanf() 
    fmt.Println(n) 
    fmt.Println(len(n)) 
} 

func scanf() []int { 
    nums := new(vector.IntVector) 
    reader := bufio.NewReader(os.Stdin) 
    str, err := reader.ReadString('\n') 
    for err != os.EOF { 
     fields := strings.Fields(str) 
     for _, f := range fields { 
      i, _ := strconv.Atoi(f) 
      nums.Push(i) 
     } 
     str, err = reader.ReadString('\n') 
    } 
    r := make([]int, nums.Len()) 
    for i := 0; i < nums.Len(); i++ { 
     r[i] = nums.At(i) 
    } 
    return r 
} 

Versione migliorata:

package main 

import (
    "bufio" 
    "os" 
    "io" 
    "fmt" 
    "strings" 
    "strconv" 
    "container/vector" 
) 

func main() { 
    n := fscanf(os.Stdin) 
    fmt.Println(len(n), n) 
} 

func fscanf(in io.Reader) []int { 
    var nums vector.IntVector 
    reader := bufio.NewReader(in) 
    str, err := reader.ReadString('\n') 
    for err != os.EOF { 
     fields := strings.Fields(str) 
     for _, f := range fields { 
      if i, err := strconv.Atoi(f); err == nil { 
       nums.Push(i) 
      } 
     } 
     str, err = reader.ReadString('\n') 
    } 
    return nums 
} 
+2

Per ottenere risposte soddisfacenti, è necessario rispondere facilmente alle proprie domande. Ad esempio, codice che può essere facilmente copiato, incollato e compilato. Il compilatore Go non accetta i numeri di riga; non metterli nel codice di esempio. – peterSO

+2

Forse questo non esisteva quando originariamente pubblicato, ma go ha fmt.Scanf che funziona proprio come C scanf ricevendo da stdin: var numero int fmt.Scanf ("% d", & number) – Myforwik

+0

Oh mio Dio! Ho cercato per ore di ottenere un buon lettore da stdin. Amico, non riuscivo a capire come scriverlo. Grazie mille per aver postato il tuo codice –

risposta

4

Il codice aggiornato è stato molto più facile da compilare senza i numeri di riga, ma mancava il pacchetto e le istruzioni di importazione.

Guardando il tuo codice, ho notato alcune cose. Ecco la mia versione riveduta del tuo codice.

package main 

import (
    "bufio" 
    "fmt" 
    "io" 
    "os" 
    "strconv" 
    "strings" 
    "container/vector" 
) 

func main() { 
    n := scanf(os.Stdin) 
    fmt.Println() 
    fmt.Println(len(n), n) 
} 

func scanf(in io.Reader) []int { 
    var nums vector.IntVector 
    rd := bufio.NewReader(os.Stdin) 
    str, err := rd.ReadString('\n') 
    for err != os.EOF { 
     fields := strings.Fields(str) 
     for _, f := range fields { 
      if i, err := strconv.Atoi(f); err == nil { 
       nums.Push(i) 
      } 
     } 
     str, err = rd.ReadString('\n') 
    } 
    return nums 
} 

potrei voler utilizzare qualsiasi file di input per scanf(), non solo Stdin; scanf() accetta come parametro un io.Reader.

Hai scritto: nums := new(vector.IntVector), dove type IntVector []int. Questo alloca un riferimento di slice intero denominato nums e lo inizializza a zero, quindi la funzione new() alloca un riferimento a slice intero e lo inizializza a zero, quindi lo assegna a nums. Ho scritto: var nums vector.IntVector, che evita la ridondanza semplicemente assegnando un riferimento a una fetta intera di nome nums e inizializzandolo a zero.

Non è stato selezionato il valore err per strconv.Atoi(), il che significa che l'input non valido è stato convertito in un valore zero; Salto.

Per copiare dal vettore ad una nuova fetta e tornare la fetta, hai scritto:

r := make([]int, nums.Len()) 
for i := 0; i < nums.Len(); i++ { 
    r[i] = nums.At(i) 
} 
return r 

In primo luogo, ho semplicemente sostituito con un equivalente che, il metodo IntVector.Data(): return nums.Data(). Quindi, ho approfittato del fatto che type IntVector []int e ho evitato l'allocazione e la copia sostituendola con: return nums.

+0

Grazie! 1. Dalla specifica della lingua: "Quando la memoria viene allocata per memorizzare un valore, tramite una dichiarazione o chiamata make() o new(), e non viene fornita alcuna inizializzazione esplicita, alla memoria viene fornita un'inizializzazione predefinita". Allora qual è il punto di new()? 2. Ho notato "digitare IntVector [] int" per la prima volta. Go è così diverso dal C++. E poiché IntVector è di tipo int [], la funzione Data() è ridondante? –

0

Anche se può essere utilizzato per altre cose, il pacchetto dello scanner è stato progettato per eseguire la scansione di Go testo del programma. Ints (-123), Chars ('c'), Strings ("str"), ecc. Sono tipi di token in lingua Go.

package main 

import (
    "fmt" 
    "os" 
    "scanner" 
    "strconv" 
) 

func main() { 
    var s scanner.Scanner 
    s.Init(os.Stdin) 
    s.Error = func(s *scanner.Scanner, msg string) { fmt.Println("scan error", msg) } 
    s.Mode = scanner.ScanInts | scanner.ScanStrings | scanner.ScanRawStrings 
    for tok := s.Scan(); tok != scanner.EOF; tok = s.Scan() { 
     txt := s.TokenText() 
     fmt.Print("token:", tok, "text:", txt) 
     switch tok { 
     case scanner.Int: 
      si, err := strconv.Atoi64(txt) 
      if err == nil { 
       fmt.Print(" integer: ", si) 
      } 
     case scanner.String, scanner.RawString: 
      fmt.Print(" string: ", txt) 
     default: 
      if tok >= 0 { 
       fmt.Print(" unicode: ", "rune = ", tok) 
      } else { 
       fmt.Print(" ERROR") 
      } 
     } 
     fmt.Println() 
    } 
} 
0

Questo esempio legge sempre una riga alla volta e restituisce l'intera riga come una stringa. Se si desidera analizzare i valori specifici da esso è possibile.

package main 

import (
    "fmt" 
    "bufio" 
    "os" 
    "strings" 
) 

func main() { 
    value := Input("Please enter a value: ") 
    trimmed := strings.TrimSpace(value) 
    fmt.Printf("Hello %s!\n", trimmed) 
} 

func Input(str string) string { 
     print(str) 
     reader := bufio.NewReader(os.Stdin) 
     input, _ := reader.ReadString('\n') 
     return input 
} 
0

In un commento ad una delle mie risposte, hai detto:

Dal Specification Language: "Quando memoria viene allocata per memorizzare un valore, sia attraverso una dichiarazione o fare() o nuova() chiamata, e non è fornita alcuna inizializzazione esplicita , la memoria viene data un'inizializzazione predefinita ". Allora qual è il punto di new()?

Se eseguire:

package main 

import ("fmt") 

func main() { 
    var i int 
    var j *int 
    fmt.Println("i (a value) = ", i, "; j (a pointer) = ", j) 
    j = new(int) 
    fmt.Println("i (a value) = ", i, "; j (a pointer) = ", j, "; *j (a value) = ", *j) 
} 

La dichiarazione var i int alloca memoria per memorizzare un valore intero e inizializza il valore zero. La dichiarazione var j *int alloca la memoria per memorizzare un puntatore a un valore intero e inizializza il puntatore a zero (un puntatore nullo); nessuna memoria è allocata per memorizzare un valore intero. Vediamo l'output del programma simile a:

i (a value) = 0 ; j (a pointer) = <nil> 

La funzione built-in new prende un tipo T e restituisce un valore di tipo *T. La memoria è inizializzata a zero valori. La dichiarazione j = new(int) alloca la memoria per memorizzare un valore intero e inizializza il valore a zero, quindi memorizza un puntatore a questo valore intero in j. Vediamo l'output del programma simile a:

i (a value) = 0 ; j (a pointer) = 0x7fcf913a90f0 ; *j (a value) = 0 
+0

Il new() è correlato alle allocazioni stack o heap? –

+0

Gli oggetti piccoli vengono allocati dagli elenchi gratuiti della cache per thread.Gli oggetti grandi (> 32 kB) vengono allocati direttamente dall'heap. – peterSO

0

L'ultima versione di Go (2010-05-27) ha aggiunto due funzioni al pacchetto fmt: Scan() e Scanln(). Non prendono nessuna stringa di pattern. come in C, ma invece controlla il tipo degli argomenti.

package main 

import (
    "fmt" 
    "os" 
    "container/vector" 
) 

func main() { 
    numbers := new(vector.IntVector) 
    var number int 
    n, err := fmt.Scan(os.Stdin, &number) 
    for n == 1 && err == nil { 
     numbers.Push(number) 
     n, err = fmt.Scan(os.Stdin, &number) 
    } 
    fmt.Printf("%v\n", numbers.Data()) 
} 
+0

A questo punto, il 2 giugno 2010, la funzione di scansione del pacchetto fmt è un'implementazione incompleta con aggiornamenti molto frequenti e revisioni sostanziali. – peterSO

+0

Sì. Proverò a ricordare di aggiornare la risposta alla prossima versione. –