将Vec <u16>或Vec <wchar>转换为&amp; str

时间:2016-08-21 20:47:39

标签: string rust

我正在进入Rust编程实现一个小程序,我在字符串转换中有点迷失。

在我的程序中,我有一个向量如下:

let mut name: Vec<winnt::WCHAR> = Vec::new(); 

WCHAR与我的Windows计算机上的u16相同。

我将Vec<u16>移交给C函数(作为指针),用它填充数据。然后我需要将向量中包含的字符串转换为&str。但是,无论我尝试什么,我都无法让这种转换工作。

我设法完成的唯一工作就是将其转换为WideString

 widestr = unsafe { WideCString::from_ptr_str(name.as_ptr()) };

但这似乎是走向错误方向的一步。

在假设向量包含有效且以null结尾的字符串的情况下,将Vec<u16>转换为&str的最佳方法是什么。

2 个答案:

答案 0 :(得分:11)

  

然后我需要将向量中包含的字符串转换为&str。但是,无论我尝试什么,我都无法让这种转换工作。

没有办法让这个&#34;免费&#34;转换。

&str是使用UTF-8编码的Unicode字符串。这是一种面向字节的编码。如果你有UTF-16(或不同但是常见的UCS-2编码),那么就无法读取另一个。这相当于尝试将JPEG图像作为PDF读取。两个数据块都可能是一个字符串,但编码很重要。

第一个问题是&#34;你真的需要这样做吗?&#34;。很多时候,您可以从一个函数中获取数据并将其转换回另一个函数,从不查看它。如果你可以逃脱,那可能是最好的答案。

如果你需要转换它,那么你必须处理可能发生的错误。任意16位整数数组可能不是有效的UTF-16或UCS-2。这些编码具有边缘情况,可以轻松生成无效字符串。空终止是另一个方面 - Unicode实际上允许嵌入的NUL字符,因此以null结尾的字符串不能包含所有可能的Unicode字符!

一旦确保编码有效 1 并找出输入向量中有多少条目构成字符串,那么你必须解码输入格式并重新编码为输出格式。这可能需要某种新的分配,因此您最有可能最终使用String,然后可以在&str可以使用的任何地方使用。

有一种内置方法可将UTF-16数据转换为字符串:String::from_utf16。请注意,它返回Result以允许这些错误情况。还有String::from_utf16_lossy,它用Unicode替换字符替换无效的编码部分。

let name = [0x68, 0x65, 0x6c, 0x6c, 0x6f]; 

let a = String::from_utf16(&name);
let b = String::from_utf16_lossy(&name);

println!("{:?}", a);
println!("{:?}", b);

如果您从指向u16WCHAR的指针开始,则需要先使用slice::from_raw_parts转换为切片。如果您有一个以null结尾的字符串,则需要自己找到NUL并适当地切片输入。

1:这实际上是一种使用类型的好方法; &str 保证为UTF-8编码,因此无需进一步检查。同样,WideCString可能会在构建时执行一次检查,然后可以跳过以后使用的检查。

答案 1 :(得分:0)

这是我对这种情况的简单攻击。必须有一个bug;修复你自己的情况:

let mut v = vec![0u16; MAX_PATH as usize];

// imaginary win32 function
win32_function(v.as_mut_ptr());

let mut path = String::new();
for val in v.iter() {
    let c: u8 = (*val & 0xFF) as u8;
    if c == 0 {
        break;
    } else {
        path.push(c as char);
    }
}