diff --git a/columnize.go b/columnize.go index 915716a..c2c2db6 100644 --- a/columnize.go +++ b/columnize.go @@ -3,7 +3,9 @@ package columnize import ( "bytes" "fmt" + "os" "strings" + "unicode" ) // Config can be used to tune certain parameters which affect the way @@ -100,9 +102,26 @@ func elementsFromLine(config *Config, line string) []interface{} { // runeLen calculates the number of visible "characters" in a string func runeLen(s string) int { l := 0 - for _ = range s { + insideConsoleColor := false + for _, c := range s { + if c == '\x1b' { // start of esc color sequence + insideConsoleColor = true + continue + } + if insideConsoleColor { + if c == 'm' { // end of esc color sequence + insideConsoleColor = false + } + continue + } + l++ + if unicode.Is(unicode.Scripts["Han"], rune(c)) { + l++ + } + } + return l } @@ -123,6 +142,10 @@ func widthsFromLines(config *Config, lines []string) []int { } } } + + if os.Getenv("DEBUG_COL") == "1" { + fmt.Println(widths) + } return widths } @@ -158,7 +181,31 @@ func Format(lines []string, config *Config) string { fmtCache[numElems] = stringfmt } - fmt.Fprintf(buf, stringfmt, elems...) + if false { + // 原作者的逻辑 + // fmt.Fprintf("%-21s %s", "我们", "12.21.212.1"), 如果中文会有问题 + fmt.Fprintf(buf, stringfmt, elems...) + } else { + // 手动解决 + fmt.Fprintf(buf, conf.Prefix) + for col, elem := range elems { + s := elem.(string) + for _, c := range s { + fmt.Fprintf(buf, strings.Replace(string(c), "%", "%%", -1)) + } + + if col == len(elems)-1 { + // 最后一列 + fmt.Fprintf(buf, "\n") + } else { + // space padding + fmt.Fprintf(buf, strings.Repeat(" ", widths[col]-runeLen(s))) + // glue padding + fmt.Fprintf(buf, conf.Glue) + } + + } + } } // Get the string result diff --git a/columnize_test.go b/columnize_test.go index 89dabaa..e56023f 100644 --- a/columnize_test.go +++ b/columnize_test.go @@ -7,6 +7,29 @@ import ( crand "crypto/rand" ) +func TestSimpleFormatWithChinese(t *testing.T) { + lines := []string{"CPU%|IP"} + lines = append(lines, fmt.Sprintf("%s|%s", "阿尔法项目", "10.187.131.227")) + lines = append(lines, fmt.Sprintf("%s|%s", "ide.cc.polaris.jd.com", "10.191.92.130")) + + println(Format(lines, &Config{Glue: " ", Empty: " "})) + println() + fmt.Printf("%-21s %s\n", "阿尔法项目", "abc") + fmt.Printf("%-21s %s\n", "ide.cc.polaris.jd.com", "cm") +} + +func TestRuneLen(t *testing.T) { + if runeLen("ab") != 2 { + t.Fatalf("ab should 2") + } + if runeLen("我") != 2 { + t.Fatalf("我 should 2") + } + if runeLen("我b") != 3 { + t.Fatalf("我b should 3") + } +} + func TestListOfStringsInput(t *testing.T) { input := []string{ "Column A | Column B | Column C", @@ -210,7 +233,7 @@ func TestAlternateSpacingString(t *testing.T) { } } -func TestSimpleFormat(t *testing.T) { +func TestSimpleFormatBasic(t *testing.T) { input := []string{ "Column A | Column B | Column C", "x | y | z",