我正在使用goyaml
作为YAML美化师。通过加载和转储YAML文件,我可以对其进行源格式化。我将来自YAML源文件的数据解组为结构,封装这些字节,并将字节写入输出文件。但是这个过程将我的Unicode字符串变形为引用字符串的文字版本,我不知道如何反转它。
示例输入subtitle.yaml
:
line: 你好
我已将所有内容剥离到最小的可重现问题。这是代码,使用_
来捕获不弹出的错误:
package main
import (
"io/ioutil"
//"unicode/utf8"
//"fmt"
"gopkg.in/yaml.v1"
)
type Subtitle struct {
Line string
}
func main() {
filename := "subtitle.yaml"
in, _ := ioutil.ReadFile(filename)
var subtitle Subtitle
_ = goyaml.Unmarshal(in, &subtitle)
out, _ := goyaml.Marshal(&subtitle)
//for len(out) > 0 { // For debugging, see what the runes are
// r, size := utf8.DecodeRune(out)
// fmt.Printf("%c ", r)
// out = out[size:]
//}
_ = ioutil.WriteFile(filename, out, 0644)
}
实际输出subtitle.yaml
:
line: "\u4F60\u597D"
我想在获得变量goyaml
后扭转out
中的奇怪现象。
注释掉的符文打印代码块,为了清晰起见,在符文之间添加空格,输出以下内容。它表明像你
这样的Unicode符文没有被解码,而是按字面意思对待:
l i n e : " \ u 4 F 6 0 \ u 5 9 7 D "
如何在将out
写入输出文件之前取消引用subtitle.yaml
,以便输出看起来像输入(尽管已经美化)?
所需输出line: "你好"
:
yaml_emitter_set_unicode
临时解决方案
我已经提交了https://github.com/go-yaml/yaml/issues/11。与此同时,@ bobince对encode.go
的提示有助于解决问题。它被定义为C绑定但从未被调用(或者给出了设置它的选项)!我更改了{{1}}并添加了yaml_emitter_set_unicode(&e.emitter, true)
to line 20,一切都按预期工作。最好将其设为可选项,但这需要更改Marshal API。
答案 0 :(得分:1)
有一个类似的问题,并可以应用它来规避goyaml.Marshal()中的错误。 (* Regexp)ReplaceAllFunc是您的朋友,您可以使用它来扩展字节数组中的转义Unicode符文。对于生产来说有点太脏了,但是可以用于示例; - )
package main
import (
"io/ioutil"
"unicode/utf8"
"regexp"
"strconv"
"launchpad.net/goyaml"
)
type Subtitle struct {
Line string
}
var reFind = regexp.MustCompile(`^\s*[^\s\:]+\:\s*".*\\u.*"\s*$`)
var reFindU = regexp.MustCompile(`\\u[0-9a-fA-F]{4}`)
func expandUnicodeInYamlLine(line []byte) []byte {
// TODO: restrict this to the quoted string value
return reFindU.ReplaceAllFunc(line, expandUnicodeRune)
}
func expandUnicodeRune(esc []byte) []byte {
ri, _:= strconv.ParseInt(string(esc[2:]), 16, 32)
r := rune(ri)
repr := make([]byte, utf8.RuneLen(r))
utf8.EncodeRune(repr, r)
return repr
}
func main() {
filename := "subtitle.yaml"
filenameOut := "subtitleout.yaml"
in, _ := ioutil.ReadFile(filename)
var subtitle Subtitle
_ = goyaml.Unmarshal(in, &subtitle)
out, _ := goyaml.Marshal(&subtitle)
out = reFind.ReplaceAllFunc(out, expandUnicodeInYamlLine)
_ = ioutil.WriteFile(filenameOut, out, 0644)
}