Как прочитать строку с пробелами
fmt.Scan и fmt.Scanln читают в строку только одно слово — до пробела. Строку целиком читает bufio.Scanner:
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 читает строку за строкой, пока ввод не кончится:
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)
}
}Минск, ул. Ленина
Брест
Гродно, 21: Минск, ул. Ленина
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():
scanner := bufio.NewScanner(os.Stdin)
scanner.Buffer(make([]byte, 1024*1024), 1024*1024)Теперь строка может быть длиной до мегабайта.
Другой способ: bufio.Reader
ReadString('\n') читает до перевода строки и возвращает строку вместе с ним (а в Windows — ещё и с \r). Лишнее убирают strings.TrimSpace:
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), поэтому здесь программа сдаётся, только когда строка пустая.
Подводные камни
- Не смешивайте
fmt.Scanи Scanner на одном вводе. Scanner читает ввод вперёд большими кусками, иfmt.Scanпосле него может не увидеть часть данных. Читайте всё через Scanner, а числа получайте из строк черезstrconv.Atoi(Как перевести строку в число). - Слова строки по отдельности —
strings.Fields(scanner.Text()). - Пробелы в начале и в конце Scanner не трогает — уберите их
strings.TrimSpace, если они не нужны. - Файл вместо клавиатуры читается так же: вместо
os.Stdinпередайте открытый файл изos.Open.