Отчёт по выгрузке и битые строки
Строка режется на поля, название доводится до ширины, файл читается по имени. Осталось собрать отчёт и решить, что делать с битой строкой.
Битая строка — не повод останавливаться
Ситуация. В выгрузке десять тысяч строк, в двух оператор ошибся. Остановится программа на первой — отчёта нет, о второй ошибке никто не узнает. Молча пропустит — итог соврёт, и никто не узнает почему.
Поэтому правило такое:
- битая строка — сообщение в поток ошибок с номером строки, чтобы её можно было найти в файле;
- программа идёт дальше — к следующей строке;
- после всех строк — итог и код возврата 1, если битые строки были: скрипт, запустивший отчёт, узнает, что выгрузка грязная.
Цикл отчёта:
for i, line := range lines {
name, qty, price, err := parseLine(line)
if err != nil {
fmt.Fprintf(os.Stderr, "строка %d: %v\n", i+1, err)
bad++
continue
}
fmt.Printf("%s %d шт. %d коп.\n", fitName(name, width), qty, qty*price)
count++
total += qty * price
}
fmt.Printf("Итого: %d поз., %d коп.\n", count, total)
if bad > 0 {
os.Exit(1)
}Как это читать.
| Строка | Зачем |
|---|---|
i+1 |
range считает с нуля, а строки файла — с единицы: человек откроет файл на строке 5, а не 4 |
bad++ и continue |
запомнили, что была ошибка, и перешли к следующей строке — continue из дня 08 |
Fprintf(os.Stderr, …) |
сообщение не попадёт в файл отчёта при > report.txt — день 07 |
os.Exit(1) после Итого |
os.Exit завершает программу сразу: раньше печати итога — итога не будет |
Отчёт целиком
Программа целиком — задание страницы. Её запуск с шириной 14 на таком orders.csv:
TK-101;Болт М8;12;1500
TK-102;Анкер клиновой;4;2750
TK-103;Кронштейн усиленный;200;45
TK-104;Bolt-M8;10;1400
TK-105;Шайба кровельная;100
TK-106;Хомут червячный;сто;90
TK-107;Шайба;40;350Что увидите.
stagiaire@lab:~/gocourse/day19/report$ go run .
Болт М8....... 12 шт. 18000 коп.
Анкер клиновой 4 шт. 11000 коп.
Кронштейн уси~ 200 шт. 9000 коп.
Bolt-M8....... 10 шт. 14000 коп.
строка 5: нужно 4 поля, а их 3
строка 6: количество: strconv.Atoi: parsing "сто": invalid syntax
Шайба......... 40 шт. 14000 коп.
Итого: 5 поз., 66000 коп.
exit status 1На экране оба потока вперемешку, в порядке печати. Разделить их — как в дне 07:
stagiaire@lab:~/gocourse/day19/report$ go build -o prog . && ./prog > report.txt; echo $?
строка 5: нужно 4 поля, а их 3
строка 6: количество: strconv.Atoi: parsing "сто": invalid syntax
1
stagiaire@lab:~/gocourse/day19/report$ cat report.txt
Болт М8....... 12 шт. 18000 коп.
Анкер клиновой 4 шт. 11000 коп.
Кронштейн уси~ 200 шт. 9000 коп.
Bolt-M8....... 10 шт. 14000 коп.
Шайба......... 40 шт. 14000 коп.
Итого: 5 поз., 66000 коп.Как это читать. В report.txt — чистый отчёт, сообщения с номерами строк — на экране. Код 1: отчёт есть, но в выгрузке ошибки.
Для сравнения — та же программа, где вместо bad++ и continue стоит os.Exit(1):
stagiaire@lab:~/gocourse/day19/report$ go run .
Болт М8....... 12 шт. 18000 коп.
Анкер клиновой 4 шт. 11000 коп.
Кронштейн уси~ 200 шт. 9000 коп.
Bolt-M8....... 10 шт. 14000 коп.
строка 5: нужно 4 поля, а их 3
exit status 1Ни шестой строки с ошибкой, ни седьмой верной, ни итога.
Попробуйте сейчас: задание report.
Цель:
main.goв~/gocourse/day19/reportпечатает отчёт по вашемуorders.csvровно как вTASK.txt: колонка по буквам, битые строки в поток ошибок, код возврата.1. Перечитайте условие, особенно пример — ширина колонки у вас своя:
▶ Выполнитеcd ~/gocourse/day19/report cat TASK.txt cat orders.csv2. Напишите
main.go: чтениеorders.csv— любым способом страницы 5, цикл — из раздела выше:parseLineна каждую строку, верную — черезfitName, битую — в поток ошибок, в конце итог и код.3. Проверьте на примере из условия и на файле без битых строк:
▶ Выполнитеgo run . go build -o prog . ./prog > out.txt; echo $? cat out.txt4. Проверьте ошибку открытия: переименуйте файл, запустите и верните имя:
▶ Выполнитеmv orders.csv orders.bak go run . mv orders.bak orders.csv5. Добавьте в
orders.csvсвою битую строку — с пятью полями или ценой9,90: номер в сообщении обязан совпасть с номером строки в файле. Потом уберите её.Готово, когда: вывод, поток ошибок и код совпали с примером в
TASK.txt; без файла —ошибка: open orders.csv: no such file or directoryи код 1 (пунктыreportиbroken).
Попробуйте сейчас: ритуал и коммит.
Цель: весь код дня отформатирован,
go vetмолчит, тесты зелёные, работа записана.▶ Выполнитеcd ~/gocourse/day19 gofmt -l . go vet ./... go test ./... git add . git commit -m "report: отчёт по выгрузке" git log --onelineГотово, когда:
gofmt -l .иgo vet ./...ничего не печатают,go test ./...—okуday19/report, вgit log --onelineне меньше четырёх коммитов (пунктыcode_fmtиgit).
Что может пойти не так
| Что видите | Что это значит | Что делать |
|---|---|---|
нет строки Итого |
os.Exit(1) стоит внутри цикла или раньше печати итога |
bad++ и continue в цикле, os.Exit(1) — последней строкой main |
| номера строк в сообщениях на один меньше, чем в файле | печатается i, а range считает с нуля |
i+1 |
сообщения о битых строках оказались в out.txt |
ошибка напечатана через fmt.Printf |
fmt.Fprintf(os.Stderr, …) |
echo $? печатает 0, хотя битые строки были |
в конце нет os.Exit(1) |
if bad > 0 { os.Exit(1) } после итога |
в колонке � |
название обрезано по байтам | обрезать через []rune — fitName со страницы 3 |
| на вашем файле колонка ровная, а проверка показывает кривую на другом | число точек вписано под свои названия или считается через len |
всё через fitName(название, ширина) |
| проверка: лишняя битая строка с номером за концом файла | Split после последнего перевода строки |
TrimSuffix, как в fix2 |
declared and not used: bad |
счётчик ошибок заведён, но не проверяется в конце | if bad > 0 { os.Exit(1) } |
Словарик ошибок
Допишите в ~/errors.md сообщения дня, которые встретили сами, — вместе с прошлыми днями не меньше тридцати восьми строк (пункт errors). Строка — «текст ошибки — что значило», через тире с пробелами:
panic: strings: negative Repeat count — ширину считал через len, у русского названия байтов больше ширины
open orders.csv: no such file or directory — программа запущена не из того каталога, где лежит файл
invalid operation: r + "!" (mismatched types rune and untyped string) — руна не строка, нужен string(r)Материал дня закончен. Задания — course lab 19, дополнительное чтение — course extra 19