在Go中将unicode代码点转换为文字字符



假设我有一个这样的文本文件。

u0053
u0075
u006E

有没有办法把它转换成这个?

S
u
n

目前,我使用ioutil.ReadFile("data.txt"),但当我打印数据时,我得到的是unicode代码点,而不是字符串文字。我意识到这是ReadFile的正确行为,只是我不想要。

我的目标是用它们的文字字符替换代码点。

您可以使用strconv.Unquote()strconv.UnquoteChar()函数进行转换。

您应该注意的一件事是,strconv.Unquote()只能取消引号中的字符串的引号(例如,以引号字符"或后引号字符`开头和结尾),因此我们必须手动附加它。

参见此示例:

lines := []string{
    `u0053`,
    `u0075`,
    `u006E`,
}
fmt.Println(lines)
for i, v := range lines {
    var err error
    lines[i], err = strconv.Unquote(`"` + v + `"`)
    if err != nil {
        fmt.Println(err)
    }
}
fmt.Println(lines)
fmt.Println(strconv.Unquote(`"Gou0070x68x65x72"`))

输出(在Go Playground上尝试):

[u0053 u0075 u006E]
[S u n]
Gopher <nil>

如果要取消引用的字符串包含单个rune的转义序列(或者只想取消引用第一个rune),则可以使用strconv.UnquoteChar()。这就是它的样子(注意:在这种情况下不需要引用输入,就像strconv.Unquote()一样):

runes := []string{
    `u0053`,
    `u0075`,
    `u006E`,
}
fmt.Println(runes)
for _, v := range runes {
    var err error
    value, _, _, err := strconv.UnquoteChar(v, 0)
    if err != nil {
        fmt.Println(err)
    }
    fmt.Printf("%cn", value)
}

这将输出(在Go Playground上尝试):

[u0053 u0075 u006E]
S
u
n

一种稍微不同的方法是使用strconv.ParseInt,这会生成更少的垃圾,并使用更少的内部逻辑(Unquote会进行许多其他检查)来解析行:

for i, v := range lines {
    if len(v) != 6 {
        continue
    }
    if r, err := strconv.ParseInt(v[2:], 16, 32); err == nil {
        lines[i] = string(r)
    }
}

操场

您可以使用这个:

import "github.com/chzyer/readline/runes"
// unicodeUnquote converts unicode points such as u0053 to UTF8 encoding.
func unicodeUnquote(bs []byte) []byte {
    unicodeEscapeRx := regexp.MustCompile(`\u[0-9a-fA-F]{4}`)
    return unicodeEscapeRx.ReplaceAllFunc(bs, func(code []byte) []byte {
        rune, _, _, _ := strconv.UnquoteChar(string(code), 0)
        width := runes.Width(rune)
        runeBytes := make([]byte, width)
        utf8.EncodeRune(runeBytes, rune)
        return runeBytes
    })
}

完整的示例位于https://go.dev/play/p/ElIGZvJNyEF.

最新更新