package main import ( "bufio" "bytes" "flag" "io" "os" ) var ( stdin io.Reader = os.Stdin stdout io.Writer = os.Stdout columnDelimiter string pageDelimiter string minimumInstances int ) func main() { flag.StringVar(&pageDelimiter, "p", "\f", "page delimiter character") flag.StringVar(&columnDelimiter, "d", " ", "column delimiter character") flag.IntVar(&minimumInstances, "m", 2, "minimum non-leading instances of delimiter to break a column") flag.Parse() if err := _main(); err != nil { panic(err) } } func _main() error { r := bufio.NewReader(stdin) for { b, err := readPage(r) if err != nil && err != io.EOF { return err } if err := putPage(b); err != nil { return err } if err == io.EOF { break } } return nil } func readPage(r *bufio.Reader) ([]byte, error) { return _readPage([]byte(pageDelimiter)[0], r) } func _readPage(d byte, r *bufio.Reader) ([]byte, error) { b, err := r.ReadBytes(d) if len(b) > 0 && byte(b[len(b)-1]) == d { b = b[:len(b)-1] } return b, err } func putPage(b []byte) error { return _putPage(stdout, b, []byte(columnDelimiter)[0], minimumInstances) } func _putPage(w io.Writer, b []byte, d byte, instances int) error { nonFirstColumn := []byte{} for _, line := range lines(b) { //line = bytes.TrimSpace(line) i := 0 for i < len(line) && line[i] == d { i += 1 } for i < len(line) { j := 0 for j+i < len(line) && line[i+j] == d { j += 1 } if j >= instances { nonFirstColumn = append(nonFirstColumn, line[i+j:]...) line = line[:i+j] break } i += 1 } w.Write(line) w.Write([]byte{'\n'}) } if len(nonFirstColumn) > 0 { return _putPage(w, nonFirstColumn, d, instances) } return nil } func lines(b []byte) [][]byte { return bytes.Split(b, []byte{'\n'}) }