Go版本go版本 go1.21.4 linux/amd64
go env
N/A
打开了https://pkg.go.dev/unicode/utf16#DecodeRune
页面上没有示例。
一个使用DecodeRune来解码一个 []uint16 的例子,而不需要进行堆分配,类似于 utf8.DecodeRune 的工作方式。
[]uint16
utf8.DecodeRune
cgh8pdjw1#
根据我对包的理解,这是我为了将字符串从utf8编码转换为utf16编码而编写的代码。我不得不深入研究utf16包的内部来编写这段代码,并复制粘贴了一些内容,尤其是第一个函数。将它们留在这里,因为它们将是很好的补充,以展示如何使用utf16包与其更常用的对应项utf8一起使用。
func encodeUTF16to8(dstUTF8, srcUTF16 []byte, order16 binary.ByteOrder) (int, error) { // UTF16 values. const ( // 0xd800-0xdc00 encodes the high 10 bits of a pair. // 0xdc00-0xe000 encodes the low 10 bits of a pair. // the value is those 20 bits plus 0x10000. surr1 = 0xd800 surr2 = 0xdc00 surr3 = 0xe000 surrSelf = 0x10000 ) n := 0 var r1, r2 rune for { slen := len(srcUTF16) if slen == 0 { break } r1 = rune(order16.Uint16(srcUTF16)) if slen >= 4 { r2 = rune(order16.Uint16(srcUTF16[2:])) } var ar rune switch { case r1 < surr1, surr3 <= r1: // normal rune ar = r1 srcUTF16 = srcUTF16[2:] case surr1 <= r1 && r1 < surr2 && slen >= 4 && surr2 <= r2 && r2 < surr3: // valid surrogate sequence ar = utf16.DecodeRune(r1, r2) srcUTF16 = srcUTF16[4:] default: // invalid surrogate sequence return n, errors.New("invalid utf16") } // Encode the rune into UTF-8. if utf8.RuneLen(ar) > len(dstUTF8[n:]) { return n, errors.New("insufficient utf8 buffer") } n += utf8.EncodeRune(dstUTF8[n:], ar) } return n, nil } func encodeUTF8to16(dst16, src8 []byte, order16 binary.ByteOrder) (int, error) { n := 0 for len(src8) > 0 { r1, size := utf8.DecodeRune(src8) src8 = src8[size:] switch { case utf16.IsSurrogate(r1): // Surrogate pair case. if len(dst16) < 4 { return n, errors.New("insufficient utf16 buffer") } r1, r2 := utf16.EncodeRune(r1) order16.PutUint16(dst16[n:], uint16(r1)) order16.PutUint16(dst16[n+2:], uint16(r2)) n += 4 default: // General case. if len(dst16) < 2 { return n, errors.New("insufficient utf16 buffer") } // Simplest case for ASCII characters. order16.PutUint16(dst16[n:], uint16(r1)) n += 2 } } return n, nil }
zzlelutf2#
尽管我理解您希望避免堆分配,但所有使用unicode/utf16的情况都会将此包返回的[]rune显式转换为字符串。这样做既简单又快速,代码量很少。如果那里存在瓶颈,我希望在实际应用中看到它。unicode/utf8包没有像您建议的那种跨转换,虽然公平地说,它实际上并不需要它们,因为该语言直接支持该编码。简而言之,似乎没有必要为您建议的例程添加到库中。我相信示例会很好,但它们应该展示出每个人似乎都在使用的惯用转换,而不是您在这里展示的复杂代码。
snz8szmq3#
为了澄清我措辞不当的评论:我的意思是将例程添加到pkg.go.dev中。结果证明,在“真实”的Go代码中并没有瓶颈。正如你所说,Go的垃圾回收器是业界最先进的,进行显而易见的转换很可能效果很好。问题在于在微控制器上使用TinyGo分配内存时,RAM非常有限,内存容易碎片化,最终导致程序崩溃。我理解TinyGo不是Go,一个更优雅的解决方案是在TinyGo中创建一个更强大的垃圾回收器,但这是一个艰巨的任务。总之,虽然我不建议将这些utf16-utf8转换例程作为包的一部分,而是作为使用示例,但我非常希望暴露utf16内部的某个部分。我已经在这里提出了一个提案:#65511编辑:我注意到,将#65511中提议的例程添加到其中会极大地简化其中一个转换函数:
func encodeUTF16to8(dstUTF8, srcUTF16 []byte, order16 binary.ByteOrder) (int, error) { n := 0 for len(srcUTF16) > 1 { r, size := utf16.DecodeBytes(srcUTF16, order16) if r == utf8.RuneError { return n, errors.New("invalid utf16 sequence") } srcUTF16 = srcUTF16[size:] n += utf8.EncodeRune(dstUTF8[n:], r) } return n, nil }
3条答案
按热度按时间cgh8pdjw1#
根据我对包的理解,这是我为了将字符串从utf8编码转换为utf16编码而编写的代码。我不得不深入研究utf16包的内部来编写这段代码,并复制粘贴了一些内容,尤其是第一个函数。
将它们留在这里,因为它们将是很好的补充,以展示如何使用utf16包与其更常用的对应项utf8一起使用。
zzlelutf2#
尽管我理解您希望避免堆分配,但所有使用unicode/utf16的情况都会将此包返回的[]rune显式转换为字符串。这样做既简单又快速,代码量很少。如果那里存在瓶颈,我希望在实际应用中看到它。
unicode/utf8包没有像您建议的那种跨转换,虽然公平地说,它实际上并不需要它们,因为该语言直接支持该编码。
简而言之,似乎没有必要为您建议的例程添加到库中。
我相信示例会很好,但它们应该展示出每个人似乎都在使用的惯用转换,而不是您在这里展示的复杂代码。
snz8szmq3#
为了澄清我措辞不当的评论:我的意思是将例程添加到pkg.go.dev中。
结果证明,在“真实”的Go代码中并没有瓶颈。正如你所说,Go的垃圾回收器是业界最先进的,进行显而易见的转换很可能效果很好。问题在于在微控制器上使用TinyGo分配内存时,RAM非常有限,内存容易碎片化,最终导致程序崩溃。
我理解TinyGo不是Go,一个更优雅的解决方案是在TinyGo中创建一个更强大的垃圾回收器,但这是一个艰巨的任务。
总之,虽然我不建议将这些utf16-utf8转换例程作为包的一部分,而是作为使用示例,但我非常希望暴露utf16内部的某个部分。我已经在这里提出了一个提案:#65511
编辑:我注意到,将#65511中提议的例程添加到其中会极大地简化其中一个转换函数: