유효한 WTF-8 인 16 비트 조각 집합 (Rust : &[u16]
)을 정의하려고합니다. -encoded), 유효하지 않은 UTF-8 (재 인코딩 된 경우)이 없으므로 이러한 슬라이스를 무작위로 생성 할 수 있습니다. 이것은 String
으로 구문 분석하지 않는 Windows 컴퓨터에서 가능한 모든 std::ffi::OsString
을 생성하기위한 노력의 일환입니다.잘못된 형식의 UTF-8 인 16 비트 슬라이스 인 WTF-8 문자열 집합
변환 &[u16] -> OsString
은 std::os::windows::ffi::OsStringExt::from_wide
을 통해 이루어집니다.
/// 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
을 통해 이루어집니다 :이 같은 작업을 정의 libstd/sys_common/wtf8.rs
로 리디렉션 next_surrogate
와
/// 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),
}
}
정의로 :
#[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()
은 결코 패닉을 일으키지 않습니다. OsString
을 돌려줍니다. 물론 OsString
집합은 최대가되어야하며 사소한 상수를 사용하지 않아야합니다.
Gen
입력 한 임의의 데이터를 생성하기위한 모나드의 일종이다
encode_wide : &[u8] -> &[u16]
valid_wtf8_invalid_utf8 :() -> Gen<Vec<u8>>
.
encode_wide
와 valid_wtf8_invalid_utf8()
에 의해 주어진 펑터를 매핑함으로써 우리는이에서 우리는 Gen<OsString>
을받을 수 있습니다, 차례로, Gen<Vec<u16>>
를 얻을 수 있습니다.
그러나 작업을 정의하는 방법이 확실하지 않습니다. encode_wide
및 valid_wtf8_invalid_utf8
. 주어진 함수의 논리를 뒤집기보다는 취할 수있는 좀 더 직접적인 접근법이 있습니까?
Gen
이 추상화되어 있기 때문에 실행 가능한 코드를 기대하지는 않지만 의사 코드 또는 다른 고급 명령어는 깔끔합니다. 감사합니다.)
'from_wide'. 몇 가지 문서 : https://doc.rust-lang.org/nightly/std/ffi/struct.OsString.html 특히 "Windows에서 문자열은 종종 0이 아닌 16 비트 값의 임의 시퀀스이며 UTF- 16 그렇게하는 것이 타당 할 때. " 그게 나에게 매우 혼란 스럽습니다. 알고리즘에 의해 생성 된'vec : Vec'주어진'OsString :: from_wide (vec.as_slice()). into_string(). unwrap_err()'의 결과는 결코 공황입니까? –
Centril
생성 된 시퀀스가 유효한 UTF-16이 아닐 것이라고 확신합니다 (쌍 외부에 대리가 포함되어 있기 때문에). 이러한 시퀀스는 WTF-8로 변환 할 때 유효한 UTF-8이 될 수 없습니다 (변환이 무손실이기 때문에 UTF-8을 WTF-16으로 다시 변환하면 유효한 UTF-16으로 끝나기 때문에). 그러나 무손실은 원래 유효하지 않은 UTF-16). – Stefan
바로 그 문제를 해결해 주셔서 감사합니다. 그것을 테스트하고 잘 작동하는 것 같습니다. 건배! – Centril