gpt4 book ai didi

utf-8 - 作为 16 位切片的格式错误的 UTF-8 的 WTF-8 字符串集

转载 作者:行者123 更新时间:2023-11-29 08:00:57 27 4
gpt4 key购买 nike

我正在尝试定义一组 16 位切片(Rust:&[u16]),它们是有效的 WTF-8(重新编码时),但不是有效的 UTF-8(重新编码时),所以我可以随机生成这样的切片。这是为了生成所有可能的 std::ffi::OsString s 在不解析为 String 的 Windows 机器上.

转换&[u16] -> OsString通过 std::os::windows::ffi::OsStringExt::from_wide 完成.这重定向到 libstd/sys_common/wtf8.rs将操作定义为:

/// Creates a WTF-8 string from a potentially ill-formed UTF-16 slice of 16-bit code units.
///
/// This is lossless: calling `.encode_wide()` on the resulting string
/// will always return the original code units.
pub fn from_wide(v: &[u16]) -> Wtf8Buf {
let mut string = Wtf8Buf::with_capacity(v.len());
for item in char::decode_utf16(v.iter().cloned()) {
match item {
Ok(ch) => string.push_char(ch),
Err(surrogate) => {
let surrogate = surrogate.unpaired_surrogate();
// Surrogates are known to be in the code point range.
let code_point = unsafe {
CodePoint::from_u32_unchecked(surrogate as u32)
};
// Skip the WTF-8 concatenation check,
// surrogate pairs are already decoded by decode_utf16
string.push_code_point_unchecked(code_point)
}
}
}
string
}

转换OsString -> Result<String, Wtf8Buf>通过 into_string 完成在同一个文件中:

/// Consumes the WTF-8 string and tries to convert it to UTF-8.
///
/// This does not copy the data.
///
/// If the contents are not well-formed UTF-8
/// (that is, if the string contains surrogates),
/// the original WTF-8 string is returned instead.
pub fn into_string(self) -> Result<String, Wtf8Buf> {
match self.next_surrogate(0) {
None => Ok(unsafe { String::from_utf8_unchecked(self.bytes) }),
Some(_) => Err(self),
}
}

next_surrogate定义为:

#[inline]
fn next_surrogate(&self, mut pos: usize) -> Option<(usize, u16)> {
let mut iter = self.bytes[pos..].iter();
loop {
let b = *iter.next()?;
if b < 0x80 {
pos += 1;
} else if b < 0xE0 {
iter.next();
pos += 2;
} else if b == 0xED {
match (iter.next(), iter.next()) {
(Some(&b2), Some(&b3)) if b2 >= 0xA0 => {
return Some((pos, decode_surrogate(b2, b3)))
}
_ => pos += 3
}
} else if b < 0xF0 {
iter.next();
iter.next();
pos += 3;
} else {
iter.next();
iter.next();
iter.next();
pos += 4;
}
}
}

我想做的是设计一个生成 Vec<u16> 的算法这样 OsString::from_wide(vec.as_slice()).into_string().unwrap_err()从不 panic 并返回一个OsString . OsString的一套s 当然应该是最大的,而不是使用平凡的常量。

为此,为了简化,我们可以定义两个操作:

  • encode_wide : &[u8] -> &[u16]
  • valid_wtf8_invalid_utf8 : () -> Gen<Vec<u8>>其中 Gen是某种用于生成类型化随机数据的 monad。

通过映射 valid_wtf8_invalid_utf8() 给定的仿函数与 encode_wide我们可以得到 Gen<Vec<u16>> ,反过来,我们可以得到 Gen<OsString> .

但是 - 我不确定如何定义操作 encode_widevalid_wtf8_invalid_utf8 .我可以采取一些更直接的方法而不是颠倒给定函数的逻辑吗?

Gen是抽象的我不希望得到可执行代码——但伪代码或其他高级指令会很整洁。谢谢 =)

最佳答案

我不太清楚你是想生成 WTF-16\UTF-16 还是 WTF-8\UTF-8 的字符串。我认为生成一个 WTF-16 字符串而不是有效的 UTF-16 可能更容易,所以这里是:

您需要确保至少一个(16 位)“字符”是不属于代理对的代理。 (此示例还可能在字符串中生成 NUL 字符。)

extern crate rand;

use rand::Rng;

pub fn gen_wtf16_invalid_utf16<R>(r: &mut R, len: usize) -> Vec<u16>
where
R: Rng,
{
assert!(len > 0);
let mut buf = Vec::with_capacity(len);
for _ in 0..len {
buf.push(r.next_u32() as u16);
}
// make element at position `p` a surrogate that is not part
// of a surrogate pair
let p = r.gen_range(0, len-1);
// if first elem or previous entry is not a leading surrogate
let gen_trail = (0 == p) || (0xd800 != buf[p-1] & 0xfc00);
// if last element or succeeding entry is not a traililng surrogate
let gen_lead = (p == len-1) || (0xdc00 != buf[p+1] & 0xfc00);
let (force_bits_mask, force_bits_value) = if gen_trail {
if gen_lead {
// trailing or leading surrogate
(0xf800, 0xd800)
} else {
// trailing surrogate
(0xfc00, 0xdc00)
}
} else {
// leading surrogate
debug_assert!(gen_lead);
(0xfc00, 0xd800)
};
debug_assert_eq!(0, (force_bits_value & !force_bits_mask));
buf[p] = (buf[p] & !force_bits_mask) | force_bits_value;
buf
}

fn main() {
let s = gen_wtf16_invalid_utf16(&mut rand::thread_rng(), 10);
for c in &s {
println!("0x{:04x}", c);
}
}

关于utf-8 - 作为 16 位切片的格式错误的 UTF-8 的 WTF-8 字符串集,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/47749164/

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