gpt4 book ai didi

arrays - 如何将 UTF-16 字节数组重新编码为 UTF-8?

转载 作者:行者123 更新时间:2023-12-02 01:31:40 24 4
gpt4 key购买 nike

我有一个 UTF-16 字节数组 (&[u8]),我想在 Rust 中将其解码并重新编码为 UTF-8。

在Python中我可以这样做:

array.decode('UTF-16', errors='ignore').encode('UTF-8')

如何在 Rust 中做到这一点?

最佳答案

这里的问题是 UTF-16 是为 16 位单元定义的,并且没有指定如何将两个 8 位单元(又名字节)转换为一个 16 位单元。

因此,我假设您使用的是网络字节序(即大字节序)。请注意,这可能不正确,因为 x86 处理器使用小端

因此重要的第一步是转换 u8进入u16 。在这种情况下,我将迭代它们,通过 u16:from_be_bytes() 转换它们。 ,然后将它们收集到向量中。

然后,我们可以使用 String::from_utf16() String::from_utf16_lossy() 转换Vec<u16>进入String .

String s 在 Rust 中内部表示为 UTF-8。所以我们可以通过 .as_bytes() 直接拉出UTF-8表示或 .into_bytes() .

fn main() {
let utf16_bytes: &[u8] = &[
0x00, 0x48, 0x20, 0xAC, 0x00, 0x6c, 0x00, 0x6c, 0x00, 0x6f, 0x00, 0x20, 0x00, 0x77, 0x00,
0x6f, 0x00, 0x72, 0x00, 0x6c, 0x00, 0x64, 0x00, 0x21,
];

let utf16_packets = utf16_bytes
.chunks(2)
.map(|e| u16::from_be_bytes(e.try_into().unwrap()))
.collect::<Vec<_>>();

let s = String::from_utf16_lossy(&utf16_packets);
println!("{:?}", s);

let utf8_bytes = s.as_bytes();
println!("{:?}", utf8_bytes);
}
"H€llo world!"
[72, 226, 130, 172, 108, 108, 111, 32, 119, 111, 114, 108, 100, 33]

请注意,我们必须使用 .try_into().unwrap()在我们的map()功能。这是因为.chunks_exact()不会让编译器知道我们迭代的 block 有多大。

一旦稳定下来,就会出现 array_chunks() 方法确实让编译器知道,并且会使代码更短、更快。遗憾的是,它仅在 nightly 中可用。现在。

#![feature(array_chunks)]

fn main() {
let utf16_bytes: &[u8] = &[
0x00, 0x48, 0x20, 0xAC, 0x00, 0x6c, 0x00, 0x6c, 0x00, 0x6f, 0x00, 0x20, 0x00, 0x77, 0x00,
0x6f, 0x00, 0x72, 0x00, 0x6c, 0x00, 0x64, 0x00, 0x21,
];

let utf16_packets = utf16_bytes
.array_chunks()
.cloned()
.map(u16::from_be_bytes)
.collect::<Vec<_>>();

let s = String::from_utf16_lossy(&utf16_packets);
println!("{:?}", s);

let utf8_bytes = s.as_bytes();
println!("{:?}", utf8_bytes);
}
> cargo +nightly run
"H€llo world!"
[72, 226, 130, 172, 108, 108, 111, 32, 119, 111, 114, 108, 100, 33]

这假设我们的输入完全可以转换为 u16单位。在生产代码中,建议检查字节数是否奇数。


为了通过错误处理正确编写此内容,我会将其提取到方法中并传播错误:

use thiserror::Error;

#[derive(Error, Debug)]
enum ParseUTF16Error {
#[error("UTF-16 data needs to contain an even amount of bytes")]
UnevenByteCount,
#[error("The given data does not contain valid UTF16 data")]
InvalidContent,
}

fn parse_utf16(data: &[u8]) -> Result<String, ParseUTF16Error> {
let data16 = data
.chunks(2)
.map(|e| e.try_into().map(u16::from_be_bytes))
.collect::<Result<Vec<_>, _>>()
.map_err(|_| ParseUTF16Error::UnevenByteCount)?;

String::from_utf16(&data16).map_err(|_| ParseUTF16Error::InvalidContent)
}

fn main() {
let utf16_bytes: &[u8] = &[
0x00, 0x48, 0x20, 0xAC, 0x00, 0x6c, 0x00, 0x6c, 0x00, 0x6f, 0x00, 0x20, 0x00, 0x77, 0x00,
0x6f, 0x00, 0x72, 0x00, 0x6c, 0x00, 0x64, 0x00, 0x21,
];

let s = parse_utf16(utf16_bytes).unwrap();
println!("{:?}", s);

let utf8_bytes = s.as_bytes();
println!("{:?}", utf8_bytes);
}
"H€llo world!"
[72, 226, 130, 172, 108, 108, 111, 32, 119, 111, 114, 108, 100, 33]

关于arrays - 如何将 UTF-16 字节数组重新编码为 UTF-8?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/73176253/

24 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com