在Go中输出未加引号的Unicode

时间:2014-02-11 08:39:48

标签: unicode go

我正在使用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。

1 个答案:

答案 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)                                                                                                                                                     
}