意外的代码点转换

时间:2017-09-07 10:16:11

标签: go unicode

为什么在以下应用程序中将一个字节转换为符号65533而不是132的符文?

我有ascii代码转换表(旧的ascii代码 - >新的ascii代码),我应该实现,所以我需要正确的 ascii 值(在这种情况下为132)转换器。

示例程序:

package main

import (
    "io/ioutil"
    "flag"
    "bytes"
    "fmt"
)

func converter(r rune) rune {
    fmt.Printf("%v ", int(r))
    return r
}

func main() {

    // parse the command line
    var infile string
    flag.StringVar(&infile, "in", "", "input file")
    flag.Parse()

    // read the whole file at once
    b, err := ioutil.ReadFile(infile)
    if err != nil {
        panic(err)
    }

    fmt.Printf("%v\n", b)

    // convert charset
    converted := bytes.Map(converter, b)

    fmt.Printf("\n%v\n", converted)
}

示例输入文件(十六进制):

4A 84 6C 6B 0D 0A

应用程序的示例输出:

[74 132 108 107 13 10]
74 65533 108 107 13 10
[74 239 191 189 108 107 13 10]

2 个答案:

答案 0 :(得分:1)

符文是Unicode值,而不是ASCII。所以你的字节被解释为UTF8。

如果我们查看您正在使用的功能: https://golang.org/src/bytes/bytes.go?s=9029:9081#L344

我们可以看到,对于切片中的每个字节,它都会转换为Unicode符文。

r := rune(s[i])

它的作用是从s [i]开始到UTF8字母的字节转换。

在UTF8中,一个字母即可 占用多一个字节。这与ASCII编码相反 一个字母总是需要一个字节。

您可以在此处了解有关UTF8的更多信息https://en.wikipedia.org/wiki/UTF-8

这就是你得错的原因。

要修复它,您应该使用范围循环迭代字节并将输出保存到新切片。

func converter(b byte) byte {
    fmt.Printf("%v ", int(r))
    return b
}

...

converted := make([]byte, len(b))

for i, v := range b {
   // v is your byte value - convert it here
   converted[i] = converter(v)
}

答案 1 :(得分:1)

从文本中读取字节,然后您可以在这些行上使用某些内容 - 输出中的最后一列将与ASCII值相比。

package main

import (
    "encoding/hex"
    "fmt"
    "unicode/utf8"
)

func main() {
    //s := "Hello, 世界"
    //Assuming the following is the hex you have read in from the file..
    b, err := hex.DecodeString("48656c6c6f2c20e4b896e7958c")
    if err != nil {
        fmt.Println(err)
    }
    fmt.Println(b)
    s := string(b)
    for i := 0; i < len(s); {
        r, size := utf8.DecodeRuneInString(s[i:])
        fmt.Printf("%d\t%c\t%d\n", i, r, r)
        i += size
    }
    anotherWay(s)

}
func anotherWay(s string) {
    fmt.Println("\nAnother way")
    for i, r := range s {
        fmt.Printf("%d\t%c\t%d\n", i, r, r)
    }
}

在操场上:https://play.golang.org/p/9WusGxWv8w