正确获取中文字符串的宽度

Get the width of Chinese strings correctly

我想在文本周围制作边框 这是一个测试,但我无法获得它的实际宽度。对于英文文本,它确实可以完美运行。

这是我的分析:

len 告诉我这个:

这是一个测试 18
aaaaaaaaa 10
つのだ☆HIRO 16
aaaaaaaaaa 10

runewidth.StringWidth 告诉我这个:

这是一个测试 12
aaaaaaaaa 10
つのだ☆HIRO 11
aaaaaaaaaa 10
func main() {
    fmt.Println("这是一个测试 |")
    fmt.Println("aaaaaaaaaa | 10*a")
    fmt.Println()
    fmt.Println("这是一个测试 |")
    fmt.Println("aaaaaaaaa | 9*a")
    fmt.Println()
    fmt.Println("Both are not equal to the Chinese text.")
    fmt.Println("The (pipe) lines are not under each other.")
}

问题:

如何让我的盒子(第一个屏幕截图)正确显示?

Unicode 字符(如汉字)在 Golang 中占 3 个字节,而 ASCII 仅占 1 个字节。这是设计使然。

如果要检查unicode字符的实际字符串大小,请使用unicode/utf8内置包。

fmt.Printf("String: %s\nLength: %d\nRune Length: %d\n", c, len(c), utf8.RuneCountInString(c))
// String: 这是一个测试
// Length: 18
// Rune Length: 6

更基本的计数方法是使用 for 循环。

count := 0
for range "这是一个测试" {
    count++
}
fmt.Printf("Count=%d\n", count)
// Count=6

关于表格格式的中英文字符串漂亮打印,好像没有直接的办法。在这种情况下,tabwriter 也不起作用。一个小技巧是使用 csv writer 如下:

data := [][]string{
    {"这是一个测试", "|"},
    {"aaaaaaaaaa", "|"},
    {"つのだ☆HIRO", "|"},
    {"aaaaaaaaaa", "|"},
}

w := csv.NewWriter(os.Stdout)
defer w.Flush()
w.Comma = '\t'

for _, row := range data {
    w.Write(row)
}

这应该会按预期打印数据。不幸的是,Whosebug 打印的格式与我在终端中看到的格式不同。但是 Playground 可以拯救我们。 Click Here

Note:这适用于符文大小彼此足够接近的字符串。对于更长的字符串,您需要更多的解决方法。

您的问题(如 )是一个 显示 问题,无法通过任何计数技巧解决。

当我们以英文显示可变间距或比例文本与 monospace 文本时,我们遇到了同样的问题。即比较:

mmmm, tasty
iiii, tasty?

与:

嗯嗯,好吃
三、好吃吗?

(假设您使用浏览器阅读此答案!)。我们不必打印汉字,甚至留下简单的ASCII都有问题!

您需要的是用于中文文本的等宽 显示字体 ,或者可能需要一些软件将其排版为表格形式,如何获得它是...另一个问题完全。

我想这就是你想要的

func TestChinese(t *testing.T) {
    tests := []string{
        "这是一个测试",
        "aaaaaaaaa",
        "つのだ☆HIRO",
        "aaaaaaaaaa",
        "这是aaaaa一个测试",
        "这是一个つの测试",
    }
    for _, tt := range tests {
        fmt.Printf("%s\t%d\t%d\n", tt, len([]rune(tt)), len([]byte(tt)))
    }
}

输出:

这是一个测试  6   18
aaaaaaaaa   9   9
つのだ☆HIRO    8   16
aaaaaaaaaa  10  10
这是aaaaa一个测试 11  23
这是一个つの测试    8   24