遇到一个比较奇怪的编码转换问题

go_assassin · 2023-11-09 02:19:09 · 1416 次点击 · 大约8小时之前 开始浏览    置顶
这是一个创建于 2023-11-09 02:19:09 的主题,其中的信息可能已经有所发展或是发生改变。

这段代码运行出来标题始终是乱码 没搞懂哪里错了 希望大哥们指教下

package main

import (
    "bytes"
    "fmt"
)

var OnSplitUTF8Func = func(r rune) rune {
    if r == 0x00 || r == 0x01 {
        return -1
    }
    return r
}

func main() {
    s := []byte{0, 123, 0, 34, 0, 98, 0, 48, 0, 97, 0, 100, 0, 55, 0, 99, 0, 51, 0, 57, 0, 53, 0, 51, 0, 54, 0, 54, 0, 53, 0, 55, 0, 101, 0, 49, 0, 101, 0, 57, 0, 51, 0, 52, 0, 50, 0, 50, 0, 100, 0, 48, 0, 52, 0, 50, 0, 98, 0, 97, 0, 100, 0, 97, 0, 57, 0, 53, 0, 34, 0, 58, 0, 123, 0, 34, 0, 116, 0, 105, 0, 116, 0, 108, 0, 101, 0, 34, 0, 58, 0, 34, 0, 25, 149, 239, 139, 176, 139, 85, 95, 34, 0, 44, 0, 34, 0, 117, 0, 114, 0, 108, 0, 34, 0, 58, 0, 34, 0, 101, 0, 114, 0, 114, 0, 106, 0, 46, 0, 112, 0, 104, 0, 112, 0, 34, 0, 125, 0, 125, 0}
    fmt.Printf("%#v\n", s)
    fmt.Printf("%s\n", s)
    value := bytes.Map(OnSplitUTF8Func, s)
    fmt.Printf("%#v\n", value)
    fmt.Printf("%s\n", string(value))
}

有疑问加站长微信联系(非本文作者)

入群交流(和以上内容无关):加入Go大咖交流群,或添加微信:liuxiaoyan-s 备注:入群;或加QQ群:692541889

1416 次点击  
加入收藏 微博
3 回复  |  直到 2023-11-09 10:27:15
shiguang2023
shiguang2023 · #1 · 大约1年之前

正确输出应该是啥呢?

这是我问chatgpt的结果, 你的字节数组 s 看起来是UTF-16编码的,而且是大端字节序。在Go中,你可以使用 unicode/utf16 包来解码UTF-16编码的字节。这是一个示例,展示如何将你的字节数组转换为字符串:

package main

import (
    "encoding/binary"
    "fmt"
    "unicode/utf16"
)

func main() {
    s := []byte{0, 123, 0, 34, 0, 98, 0, 48, 0, 97, 0, 100, 0, 55, 0, 99, 0, 51, 0, 57, 0, 53, 0, 51, 0, 54, 0, 54, 0, 53, 0, 55, 0, 101, 0, 49, 0, 101, 0, 57, 0, 51, 0, 52, 0, 50, 0, 50, 0, 100, 0, 48, 0, 52, 0, 50, 0, 98, 0, 97, 0, 100, 0, 97, 0, 57, 0, 53, 0, 34, 0, 58, 0, 123, 0, 34, 0, 116, 0, 105, 0, 116, 0, 108, 0, 101, 0, 34, 0, 58, 0, 34, 0, 25, 149, 239, 139, 176, 139, 85, 95, 34, 0, 44, 0, 34, 0, 117, 0, 114, 0, 108, 0, 34, 0, 58, 0, 34, 0, 101, 0, 114, 0, 114, 0, 106, 0, 46, 0, 112, 0, 104, 0, 112, 0, 34, 0, 125, 0, 125, 0}

    uints := make([]uint16, len(s)/2)
    for i := 0; i < len(uints); i++ {
        uints[i] = binary.BigEndian.Uint16(s[i*2 : i*2+2])
    }

    str := string(utf16.Decode(uints))
    fmt.Println(str)
}

这段代码首先创建一个 uint16 切片,然后遍历字节数组 s,每次取两个字节,并将它们转换为一个 uint16。然后,使用 utf16.Decode 函数将 uint16 切片解码为字符串。这次我们使用 binary.BigEndian.Uint16 来处理大端字节序。

{"b0ad7c39536657e1e93422d042bada95":{"title":"闯记譕弢,"url":"errj.php"}}

shiguang2023
shiguang2023 · #2 · 大约1年之前

这段代码的问题在于,它试图将字节切片(bytes slice)直接转换为字符串(string),但是没有指定正确的字符编码。在Go中,当你尝试将字节切片转换为字符串时,你需要提供一个字符编码,例如"utf-8"。

你可以通过在fmt.Printf("%s\n", s)和fmt.Printf("%s\n", string(value))这两行代码中添加"utf-8"来解决这个问题。修改后的代码如下:

package main

import (
    "bytes"
    "fmt"
)

var OnSplitUTF8Func = func(r rune) rune {
    if r == 0x00 || r == 0x01 {
        return -1
    }
    return r
}

func main() {
    s := []byte{0, 123, 0, 34, 0, 98, 0, 48, 0, 97, 0, 100, 0, 55, 0, 99, 0, 51, 0, 57, 0, 53, 0, 51, 0, 54, 0, 54, 0, 53, 0, 55, 0, 101, 0, 49, 0, 101, 0, 57, 0, 51, 0, 52, 0, 50, 0, 50, 0, 100, 0, 48, 0, 52, 0, 50, 0, 98, 0, 97, 0, 100, 0, 97, 0, 57, 0, 53, 0, 34, 0, 58, 0, 123, 0, 34, 0, 116, 0, 105, 0, 116, 0, 108, 0, 101, 0, 34, 0, 58, 0, 34, 0, 25, 149, 239, 139, 176, 139, 85, 95, 34, 0, 44, 0, 34, 0, 117, 0, 114, 0, 108, 0, 34, 0, 58, 0, 34, 0, 101, 0, 114, 0, 114, 0, 106, 0, 46, 0, 112, 0, 104, 0, 112, 0, 34, 0, 125, 0, 125, 0}
    fmt.Printf("%#v\n", s)
    fmt.Printf("%s\n", string(s)) // utf-8 encoding is added here
    value := bytes.Map(OnSplitUTF8Func, s)
    fmt.Printf("%#v\n", value)
    fmt.Printf("%s\n", string(value)) // utf-8 encoding is added here
}
go_assassin
go_assassin · #3 · 大约1年之前
shiguang2023shiguang2023 #1 回复

正确输出应该是啥呢? 这是我问chatgpt的结果, 你的字节数组 s 看起来是UTF-16编码的,而且是大端字节序。在Go中,你可以使用 unicode/utf16 包来解码UTF-16编码的字节。这是一个示例,展示如何将你的字节数组转换为字符串: ``` package main import ( "encoding/binary" "fmt" "unicode/utf16" ) func main() { s := []byte{0, 123, 0, 34, 0, 98, 0, 48, 0, 97, 0, 100, 0, 55, 0, 99, 0, 51, 0, 57, 0, 53, 0, 51, 0, 54, 0, 54, 0, 53, 0, 55, 0, 101, 0, 49, 0, 101, 0, 57, 0, 51, 0, 52, 0, 50, 0, 50, 0, 100, 0, 48, 0, 52, 0, 50, 0, 98, 0, 97, 0, 100, 0, 97, 0, 57, 0, 53, 0, 34, 0, 58, 0, 123, 0, 34, 0, 116, 0, 105, 0, 116, 0, 108, 0, 101, 0, 34, 0, 58, 0, 34, 0, 25, 149, 239, 139, 176, 139, 85, 95, 34, 0, 44, 0, 34, 0, 117, 0, 114, 0, 108, 0, 34, 0, 58, 0, 34, 0, 101, 0, 114, 0, 114, 0, 106, 0, 46, 0, 112, 0, 104, 0, 112, 0, 34, 0, 125, 0, 125, 0} uints := make([]uint16, len(s)/2) for i := 0; i < len(uints); i++ { uints[i] = binary.BigEndian.Uint16(s[i*2 : i*2+2]) } str := string(utf16.Decode(uints)) fmt.Println(str) } ``` 这段代码首先创建一个 uint16 切片,然后遍历字节数组 s,每次取两个字节,并将它们转换为一个 uint16。然后,使用 utf16.Decode 函数将 uint16 切片解码为字符串。这次我们使用 binary.BigEndian.Uint16 来处理大端字节序。 `{"b0ad7c39536657e1e93422d042bada95":{"title":"闯记譕弢,"url":"errj.php"}}`

正常的title这里应该是一个像。密码错误这样的4个字的简体中文

添加一条新回复 (您需要 登录 后才能回复 没有账号 ?)
  • 请尽量让自己的回复能够对别人有帮助
  • 支持 Markdown 格式, **粗体**、~~删除线~~、`单行代码`
  • 支持 @ 本站用户;支持表情(输入 : 提示),见 Emoji cheat sheet
  • 图片支持拖拽、截图粘贴等方式上传