Глиф Учебники

Как прочитать строку с пробелами

Справочник · Go · 2 минуты чтения

fmt.Scan и fmt.Scanln читают в строку только одно слово — до пробела. Строку целиком читает bufio.Scanner:

Go
package main

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

func main() {
    scanner := bufio.NewScanner(os.Stdin)
    if scanner.Scan() {
        line := scanner.Text()
        fmt.Printf("прочитано: %q\n", line)
    }
}
Ввод
Анна Иванова
Вывод
прочитано: "Анна Иванова"

scanner.Scan() читает очередную строку и возвращает true, если она есть, а scanner.Text() отдаёт её без перевода строки в конце. Символ \r, который добавляет Windows, тоже убирается.

Все строки до конца ввода

Scan() в цикле for читает строку за строкой, пока ввод не кончится:

Go
package main

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

func main() {
    scanner := bufio.NewScanner(os.Stdin)
    count := 0
    for scanner.Scan() {
        count++
        fmt.Printf("%d: %s\n", count, scanner.Text())
    }
    if err := scanner.Err(); err != nil {
        fmt.Fprintln(os.Stderr, "ошибка чтения:", err)
    }
}
Ввод
Минск, ул. Ленина
Брест
Гродно, 2
Вывод
1: Минск, ул. Ленина
2: Брест
3: Гродно, 2

С клавиатуры конец ввода обозначают сочетанием Ctrl+D в Linux и macOS или Ctrl+Z и Enter в Windows. Если ввод перенаправлен из файла (go run . < data.txt в bash и cmd; PowerShell знак < не поддерживает), цикл закончится сам на последней строке. После цикла проверяют scanner.Err(): Scan() возвращает false и в конце ввода, и при ошибке.

Очень длинные строки

По умолчанию Scanner читает строки длиной до 64 КБ. Строка длиннее даёт ошибку bufio.Scanner: token too long, и цикл обрывается. Если ждёте длинные строки, увеличьте буфер до первого Scan():

Go
scanner := bufio.NewScanner(os.Stdin)
scanner.Buffer(make([]byte, 1024*1024), 1024*1024)

Теперь строка может быть длиной до мегабайта.

Другой способ: bufio.Reader

ReadString('\n') читает до перевода строки и возвращает строку вместе с ним (а в Windows — ещё и с \r). Лишнее убирают strings.TrimSpace:

Go
package main

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

func main() {
    reader := bufio.NewReader(os.Stdin)
    line, err := reader.ReadString('\n')
    if err != nil && line == "" {
        fmt.Println("ничего не введено")
        return
    }
    line = strings.TrimSpace(line)
    fmt.Println("Здравствуйте,", line)
}
Ввод
Борис Петров
Вывод
Здравствуйте, Борис Петров

Если последняя строка не заканчивается переводом строки, ReadString вернёт её вместе с ошибкой io.EOF («ввод кончился», end of file), поэтому здесь программа сдаётся, только когда строка пустая.

Подводные камни