Ищете Go эквивалент Scanf - PullRequest
6 голосов
/ 10 марта 2010

Я ищу Go-эквивалент для 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 }

Я запускаю его с помощью ввода из текста со строкой целых чисел. Но он всегда выдает -3 -3 ...

А как отсканировать строку, составленную из строки и нескольких целых чисел? Смена режима, когда вы сталкиваетесь с новым типом данных?

Пакетная документация:

Пакетный сканер

Сканер общего назначения для UTF-8 закодированный текст.

Но похоже, что сканер не для общего пользования.

Обновленный код:

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
}

Улучшенная версия:

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
}

Ответы [ 5 ]

4 голосов
/ 12 марта 2010

Ваш обновленный код было гораздо проще компилировать без номеров строк, но в нем отсутствовали операторы package и import.

Глядя на твой код, я заметил несколько вещей. Вот мой пересмотренный вариант вашего кода.

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
}

Я мог бы хотеть использовать любой входной файл для scanf(), а не только Stdin; scanf() принимает io.Reader в качестве параметра.

Вы писали: nums := new(vector.IntVector), где type IntVector []int. Это выделяет целочисленную ссылку на срез с именем nums и инициализирует ее нулем, затем функция new() выделяет целочисленную ссылку на срез и инициализирует ее нулем, а затем назначает ее nums. Я написал: var nums vector.IntVector, что позволяет избежать избыточности, просто выделяя ссылку на целочисленный фрагмент с именем nums и инициализируя ее нулем.

Вы не проверяли значение err для strconv.Atoi(), что означало, что неверный ввод был преобразован в нулевое значение; Я пропускаю это.

Чтобы скопировать из вектора в новый срез и вернуть срез, вы написали:

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

Сначала я просто заменил его на эквивалентный метод IntVector.Data(): return nums.Data(). Затем я воспользовался тем, что type IntVector []int, и избежал выделения и копирования, заменив это на: return nums.

0 голосов
/ 02 июня 2010

Последняя версия Go (2010-05-27) добавила две функции в пакет fmt: Scan() и Scanln(). Они не берут какую-либо строку шаблона. как в C, но вместо этого проверяет тип аргументов.

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 голосов
/ 12 марта 2010

В комментарии к одному из моих ответов вы сказали:

Из спецификации языка: «Когда память выделяется для хранения значения, либо через объявление, либо make () или вызов new () без явного инициализация обеспечена, память дается инициализация по умолчанию ". Тогда какой смысл новой ()?

Если мы запустим:

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)
}

Объявление var i int выделяет память для хранения целочисленного значения и инициализирует значение в ноль. Объявление var j *int выделяет память для хранения указателя на целочисленное значение и инициализирует указатель на ноль (нулевой указатель); память не выделяется для хранения целочисленных значений. Мы видим вывод программы, похожий на:

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

Встроенная функция new принимает тип T и возвращает значение типа *T. Память инициализируется нулевыми значениями. Оператор j = new(int) выделяет память для хранения целочисленного значения и инициализирует значение нулем, а затем сохраняет указатель на это целое значение в j. Мы видим вывод программы, похожий на:

i (a value) =  0 ; j (a pointer) =  0x7fcf913a90f0 ; *j (a value) =  0
0 голосов
/ 10 марта 2010

Этот пример всегда читает строку за раз и возвращает всю строку как строку. Если вы хотите проанализировать конкретные значения из него, вы можете.

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 голосов
/ 10 марта 2010

Хотя он может использоваться для других целей, пакет сканера предназначен для сканирования текста программы Go. Ints (-123), Chars ('c'), Strings ("str") и т. Д. Являются типами токенов языка 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()
    }
}
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...