package console import ( "bytes" "fmt" "strings" "unicode/utf8" ) type Table [][]interface{} type Options struct { Bordered bool Header bool } func printBorder(w *bytes.Buffer, ws []int) { for _, l := range ws { w.WriteString("+") w.WriteString(strings.Repeat("-", l+2)) } w.WriteString("+\n") } func calcCharsetWidth(s string) int { bl := len(s) ul := utf8.RuneCountInString(s) if bl == ul { return bl } else { var wc int //计算中文词语数量,并且替换为2个长度显示 for wc = ((bl - ul) / 3); wc < ul; wc++ { if wc*3-wc == bl-ul { break } } wv := wc*2 + (ul - wc) return wv } } func Pretty(values Table, opts *Options) []byte { columns := make([][]string, 0) var widths []int var width int var maxLength int if opts == nil { opts = &Options{} } calcWidth := calcCharsetWidth for _, value := range values { if len(value) > maxLength { maxLength = len(value) } } widths = make([]int, maxLength) for _, vs := range values { vl := len(vs) column := make([]string, vl) for i, val := range vs { str := fmt.Sprint(val) if vl > 1 { width = calcWidth(str) if width > widths[i] { widths[i] = width } } column[i] = str } columns = append(columns, column) } buffer := &bytes.Buffer{} if opts.Bordered { printBorder(buffer, widths) } for index, column := range columns { cl := len(column) for i, w := range widths { if opts.Bordered { buffer.WriteString("|") } var str string if cl > i { str = column[i] } if opts.Bordered { buffer.WriteString(" ") } buffer.WriteString(str) cl := calcWidth(str) if widths[i] >= cl { buffer.WriteString(strings.Repeat(" ", w-cl)) } buffer.WriteString(" ") //key value options if len(widths) == 2 && i == 0 && len(column) == 2 && !opts.Bordered && !opts.Header { buffer.WriteString("\t") } } if opts.Bordered { buffer.WriteString("|\n") } else { buffer.WriteString("\n") } if opts.Header && index == 0 { printBorder(buffer, widths) } } if opts.Bordered { printBorder(buffer, widths) } return buffer.Bytes() }