package main

import (
	"fmt"
	"github.com/mattn/go-runewidth"
	"regexp"
	"unicode/utf8"
)

var stripAnsiEscapeRegexp = regexp.MustCompile(`(\x9B|\x1B\[)[0-?]*[ -/]*[@-~]`)

func stripAnsiEscape(s string) string {
	return stripAnsiEscapeRegexp.ReplaceAllString(s, "")
}

func realLength(s string) int {
	return runewidth.StringWidth(stripAnsiEscape(s))
}

func main() {
	test1 := "1234567890\t"
	test2 := "1测试长度3\t"

	fmt.Println("字符串长度,包括控制码,一个汉字长度3")
	fmt.Printf("str = %q \tlen(str) = %d\r\n", test1, len(test1))
	fmt.Printf("str = %q \tlen(str) = %d\r\n", test2, len(test2))

	fmt.Println()
	fmt.Println("字符串长度,包括控制码,一个汉字长度1")
	fmt.Printf("str = %q \tRuneCountInString(str) = %d\r\n", test1, utf8.RuneCountInString(test1))
	fmt.Printf("str = %q \tRuneCountInString(str) = %d\r\n", test2, utf8.RuneCountInString(test2))

	fmt.Println()
	fmt.Println("字符串长度,不包括控制码,一个汉字长度2,常用于计算实际的显示宽度")
	fmt.Printf("str = %q \trealLength(str) = %d\r\n", test1, realLength(test1))
	fmt.Printf("str = %q \trealLength(str) = %d\r\n", test2, realLength(test2))
}

运行结果:

字符串长度,包括控制码,一个汉字3长度
str = "1234567890\t"    len(str) = 11
str = "1测试长度3\t"    len(str) = 15

字符串长度,包括控制码,一个汉字1长度
str = "1234567890\t"    RuneCountInString(str) = 11
str = "1测试长度3\t"    RuneCountInString(str) = 7

字符串长度,不包括控制码,一个汉字2长度,真实的显示宽度
str = "1234567890\t"    realLength(str) = 10
str = "1测试长度3\t"    realLength(str) = 10