123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138 |
- package console
- import (
- "bytes"
- "fmt"
- "strings"
- "time"
- "unicode/utf8"
- )
- type Table struct {
- Bordered bool
- Values [][]interface{}
- }
- func (table *Table) AddRow(vs ...interface{}) {
- table.Values = append(table.Values, vs)
- }
- func (table *Table) WithBordered() *Table {
- table.Bordered = true
- return table
- }
- 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 (table *Table) toString(v interface{}) string {
- switch t := v.(type) {
- case float32, float64:
- return fmt.Sprintf("%.2f", t)
- case time.Time:
- return t.Format("2006-01-02 15:04:05")
- default:
- return fmt.Sprint(v)
- }
- }
- func (table *Table) Marshal() ([]byte, error) {
- columns := make([][]string, 0)
- var widths []int
- var width int
- var maxLength int
- calcWidth := calcCharsetWidth
- for _, value := range table.Values {
- if len(value) > maxLength {
- maxLength = len(value)
- }
- }
- widths = make([]int, maxLength)
- for _, vs := range table.Values {
- vl := len(vs)
- column := make([]string, vl)
- for i, val := range vs {
- str := table.toString(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 table.Bordered {
- printBorder(buffer, widths)
- }
- for index, column := range columns {
- cl := len(column)
- for i, w := range widths {
- if table.Bordered {
- buffer.WriteString("|")
- }
- var str string
- if cl > i {
- str = column[i]
- }
- if table.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 && !table.Bordered {
- buffer.WriteString("\t")
- }
- }
- if table.Bordered {
- buffer.WriteString("|\n")
- } else {
- buffer.WriteString("\n")
- }
- if table.Bordered && index == 0 {
- printBorder(buffer, widths)
- }
- }
- if table.Bordered {
- printBorder(buffer, widths)
- }
- return buffer.Bytes(), nil
- }
- func NewTable() *Table {
- return &Table{
- Bordered: false,
- Values: make([][]interface{}, 0),
- }
- }
|