如何在 Golang 中将一个 rune 转换成类似于 `\u554a` 的 Unicode 格式字符串?

21
如果你运行 fmt.Println("\u554a"),它会显示 '啊'。
但是如何从字符 '啊' 获取 unicode 风格的字符串 \u554a

你为什么想要这样做? - newacct
1
在JSON数据中,使用\uXXXX格式代替非ASCII字符(如“世界”)是非常常见的。请尝试使用jquery.getJSON()加载以下JSON数据:{"one": "\u554a ", "two": "啊"}。在页面上,您会发现其中一个正常显示,但另一个则显示乱码。 - hardPass
3
非 ASCII 字符可以在 JSON 中使用,这是正确的。但您应该知道,并不是所有商务系统都处理 utf-8 编码。您如何处理来自不同系统、使用不同编码的不同数据?也许这对您来说并不常见。我猜想您有更好的主意。 - hardPass
每当你传输文本时,双方都需要确切地知道使用的编码方式。 - newacct
常见或不常见并不是非常重要的。可能有比这个转换更好的方法。 在我的业务EDI中,这样的问题经常出现。而这种Unicode风格的转换现在是最佳实践。 当然,我问客户为什么不使用UTF-8作为标准。 - hardPass
显示剩余4条评论
8个回答

18
package main

import "fmt"
import "strconv"

func main() {
    quoted := strconv.QuoteRuneToASCII('啊') // quoted = "'\u554a'"
    unquoted := quoted[1:len(quoted)-1]      // unquoted = "\u554a"
    fmt.Println(unquoted)
}

这将输出:

\u554a

官方包中有一个带引号的 RuneToASCII 版本,但为什么不直接给我们没有引号的函数呢?我担心这样做不够整洁,因为要处理引号。所以我只是在上面给出了一个名为 RuneToASCII 的函数。这似乎更有效率。 - hardPass
@hardPass 我稍微更喜欢我的方式,但我也喜欢你的方式,我能理解为什么你更喜欢它。这是你的问题,随意将自己的答案标记为所选答案。 - Darshan Rivka Whittle
有没有另一个函数可以反过来转换?\u554a -> 啊? - 425nesp

13

在我看来,它应该更好:

func RuneToAscii(r rune) string {
    if r < 128 {
        return string(r)
    } else {
        return "\\u" + strconv.FormatInt(int64(r), 16)
    }
}

4
您可以使用fmt.Sprintf%U一起获取十六进制值:
test = fmt.Sprintf("%U", '啊')
fmt.Println("\\u" + test[2:]) // Print \u554A

你是对的。只需将其转换为十六进制值即可。而且这个函数应该更有效率:func RuneToAscii(r rune) string,如上所示。 - hardPass
Sprintf()像所有的printf()函数一样,使用反射来确定参数类型。与已经了解数据类型的特殊目的函数RuneToAscii()或QuoteRuneToASCII()相比,反射通常是一项昂贵的操作。是的,我们在这里讨论的是毫秒甚至更短的时间,但如果您在几万次循环中执行此操作,这些毫秒就会累积起来。仅供参考。 - Ronald Currier

1
package main

import "fmt"

func main() {
    fmt.Printf("%+q", '啊')
}

1
例如,
package main

import "fmt"

func main() {
    r := rune('啊')
    u := fmt.Sprintf("%U", r)
    fmt.Println(string(r), u)
}

输出:

啊 U+554A

2
在 JSON 中,通常使用\u554A而不是U+554A。要获取\u554A,仍需要进行一些额外的操作。这并不够简洁。 - hardPass

1
fmt.Printf("\\u%X", '啊')

http://play.golang.org/p/Jh9ns8Qh15

(大写或小写的 'x' 将控制十六进制字符的大小写)

正如 fmt 包的 文档 所示:

%U Unicode 格式:U+1234;与 "U+%04X" 相同


当输入已经是 ASCII 时,我希望它保持不变。比如说输入 'a',则返回 'a' 而非 '\u61'。我应该提前说明这一点。看来你们似乎不将此视为常见需求,我真的很困惑。但没关系,我已经有一个函数可以完成我的工作了。 - hardPass
这应该是最佳答案 -- 完全不需要 strconv 包。 - xpt

0

这样就可以完成工作了。

package main

import (
    "fmt"
)

func main() {
    str := fmt.Sprintf("%s", []byte{0x80})
    fmt.Println(str)
}

0
我想要补充一下hardPass的回答。
在unicode的十六进制表示中,如果少于4个字符(比如ü),strconv.FormatInt将会导致\ufc,这将在Go中导致Unicode语法错误。与Go理解的完整的\u00fc相反。
使用fmt.Sprintf和十六进制格式化填充零可以解决这个问题:
func RuneToAscii(r rune) string {
    if r < 128 {
        return string(r)
    } else {
        return fmt.Sprintf("\\u%04x", r)
    }
}

https://play.golang.org/p/80w29oeBec1


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接