package main import ( "bufio" "bytes" "fmt" "io" "strconv" "strings" ) type idRange struct { from, to uint } func readRanges(r io.Reader) ([]idRange, error) { sc := bufio.NewScanner(r) sc.Split(scanSimpleCSV) var ranges []idRange for sc.Scan() { before, after, ok := strings.Cut(sc.Text(), "-") if !ok { return nil, fmt.Errorf("range %q: missing dash", sc.Text()) } from, err := strconv.ParseUint(before, 10, 0) if err != nil { return nil, fmt.Errorf("range %q: %w", sc.Text(), err) } to, err := strconv.ParseUint(after, 10, 0) if err != nil { return nil, fmt.Errorf("range %q: %w", sc.Text(), err) } if from > to { return nil, fmt.Errorf("range %q: refers from higher to lower", sc.Text()) } ranges = append(ranges, idRange{ from: uint(from), to: uint(to), }) } return ranges, sc.Err() } func scanSimpleCSV(data []byte, atEOF bool) (advance int, token []byte, err error) { if atEOF && len(data) == 0 { return 0, nil, nil } if i := bytes.IndexByte(data, ','); i >= 0 { return i + 1, data[:i], nil } if atEOF { if trimmed, ok := bytes.CutSuffix(data, []byte("\r\n")); ok { return len(data), trimmed, nil } if trimmed, ok := bytes.CutSuffix(data, []byte{'\n'}); ok { return len(data), trimmed, nil } return len(data), data, nil } return 0, nil, nil }