2010-03-10 9 views
6

Estoy buscando el equivalente Go de scanf(). he intentado con el código siguiente:En busca de Go equivalente de 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 funciono con el aporte de un texto con una línea de números enteros. Pero siempre sale -3 -3 ...

¿Y cómo escanear una línea compuesta de una cadena y algunos enteros? ¿Cambiando el modo siempre que encuentre un nuevo tipo de datos?

La documentación del paquete:

escáner paquete

Un escáner de propósito general para UTF-8 texto codificado.

Pero parece que el escáner no es para uso general.

código Actualizado:

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 
} 

Versión mejorada:

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

Para obtener buenas respuestas, necesita hacer que sus preguntas sean fáciles de responder. Por ejemplo, código que se puede copiar, pegar y compilar fácilmente. El complemento Go no acepta números de línea; no los pongas en tu código de muestra. – peterSO

+2

Quizás esto no existió cuando se publicó originalmente, pero ve tiene fmt.Scanf que funciona igual que C scanf obteniendo de stdin: var número int fmt.Scanf ("% d", y número) – Myforwik

+0

¡Oh, Dios mío! He estado intentando durante horas obtener un buen lector de stdin. Hombre, no pude entender cómo escribirlo. Muchas gracias por publicar su código –

Respuesta

4

Su código actualizado era mucho más fácil de compilar sin los números de línea, pero faltaba el paquete y las instrucciones de importación.

Al observar su código, noté algunas cosas. Aquí está mi versión revisada de tu código.

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 
} 

puede ser que quiera utilizar cualquier archivo de entrada para scanf(), no sólo Stdin; scanf() toma un io.Reader como parámetro.

Usted escribió: nums := new(vector.IntVector), donde type IntVector []int. Esto asigna una referencia de sector entero denominada nums y la inicializa a cero, luego la función new() asigna una referencia de sector entero e inicializa a cero, y luego lo asigna a nums. Escribí: var nums vector.IntVector, que evita la redundancia simplemente asignando una referencia de sector entero llamado nums e inicializándola a cero.

No revisó el valor err para strconv.Atoi(), lo que significa que la entrada no válida se convirtió en un valor cero; Lo salteo

Para copiar desde el vector a un nuevo segmento y volver la rodaja, que escribió:

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

En primer lugar, simplemente se sustituye con un equivalente de que, el método IntVector.Data(): return nums.Data(). Luego, aproveché el hecho de que type IntVector []int y evité la asignación y copié reemplazando eso por: return nums.

+0

¡Gracias! 1. De la especificación de idioma: "Cuando se asigna memoria para almacenar un valor, ya sea a través de una declaración o de una llamada make() o nueva(), y no se proporciona una inicialización explícita, la memoria recibe una inicialización predeterminada". Entonces, ¿qué sentido tiene new()? 2. Noté "tipo IntVector [] int" por primera vez. Go es tan diferente de C++. Y como IntVector es tipo int [], ¿la función Data() es redundante? –

0

A pesar de que se puede utilizar para otras cosas, el paquete de escáner está diseñado para escanear texto del programa Go. Ints (-123), Chars ('c'), Strings ("str"), etc. son Go to language token types.

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

Este ejemplo siempre se lee en línea a la vez y devuelve toda la línea como una cadena. Si desea analizar valores específicos desde allí, podría hacerlo.

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

En un comentario a una de mis respuestas, usted dijo:

De la Especificación del lenguaje: "Cuando se asigna memoria para almacenar un valor, ya sea a través de una declaración o realizar() o una nueva(), y no se proporciona ninguna inicialización explícita , la memoria recibe una inicialización predeterminada ". Entonces, ¿qué sentido tiene new()?

si corremos:

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 declaración var i int asigna memoria para almacenar un valor entero e inicializa el valor a cero. La declaración var j *int asigna memoria para almacenar un puntero a un valor entero e inicializa el puntero a cero (un puntero nulo); no se asigna memoria para almacenar un valor entero. Vemos la salida del programa similar a:

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

La función incorporada new toma un tipo T y devuelve un valor de tipo *T. La memoria se inicializa a valores cero. La instrucción j = new(int) asigna memoria para almacenar un valor entero e inicializa el valor a cero, luego almacena un puntero a este valor entero en j. Vemos la salida del programa similar a:

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

¿Nuevo() relacionado con las asignaciones de pila o montón? –

+0

Los objetos pequeños se asignan de las listas libres del caché por subproceso.Los objetos grandes (> 32 kB) se asignan directamente desde el montón. – peterSO

0

La última versión de Go (2010-05-27) ha añadido dos funciones al paquete fmt: Scan() y Scanln(). No toman ninguna cadena de patrón. como en C, pero en su lugar verifica el tipo de argumentos.

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

En este momento, el 2 de junio de 2010, la característica de escaneo del paquete fmt es una implementación incompleta con actualizaciones muy frecuentes y revisiones sustanciales. – peterSO

+0

Sí. Trataré de recordar actualizar la respuesta en la próxima versión. –