如何将Rust字符串转换为UTF-16?

时间:2014-08-08 06:36:08

标签: string rust utf-16

  

编者注:此代码示例来自1.0之前的Rust版本,并且不是有效的Rust 1.0代码,但答案仍然包含有价值的信息。

我想将字符串文字传递给Windows API。许多Windows函数使用UTF-16作为字符串编码,而Rust的本机字符串是UTF-8。

我知道Rust有utf16_units()生成一个UTF-16字符迭代器,但我不知道如何使用该函数生成一个UTF-16字符串,其中零作为最后一个字符。

我正在制作这样的UTF-16字符串,但我确信有更好的方法来制作它:

extern "system" {
    pub fn MessageBoxW(hWnd: int, lpText: *const u16, lpCaption: *const u16, uType: uint) -> int;
}

pub fn main() {
    let s1 = [
        'H' as u16, 'e' as u16, 'l' as u16, 'l' as u16, 'o' as u16, 0 as u16,
    ];
    unsafe {
        MessageBoxW(0, s1.as_ptr(), 0 as *const u16, 0);
    }
}

3 个答案:

答案 0 :(得分:8)

Rust 1.8 +

str::encode_utf16是UTF-16值的稳定迭代器。

您只需要在该迭代器上使用collect()来构建Vec<u16>,然后在该向量上构建push(0)

pub fn main() {
    let s = "Hello";

    let mut v: Vec<u16> = s.encode_utf16().collect();
    v.push(0);
}

Rust 1.0 +

str::utf16_units() / str::encode_utf16不稳定。另一种方法是切换到夜间(如果您正在编写程序,而不是库,这是一个可行的选项)或使用像encoding这样的外部包:

extern crate encoding;

use std::slice;

use encoding::all::UTF_16LE;
use encoding::{Encoding, EncoderTrap};

fn main() {
    let s = "Hello";

    let mut v: Vec<u8> = UTF_16LE.encode(s, EncoderTrap::Strict).unwrap();
    v.push(0); v.push(0);
    let s: &[u16] = unsafe { slice::from_raw_parts(v.as_ptr() as *const _, v.len()/2) };
    println!("{:?}", s);
}

(如果您想要&mut [u16]),可以使用from_raw_parts_mut

但是,在此特定示例中,您必须小心使用字节序,因为UTF_16LE编码为您提供了以小端字节顺序表示u16的字节向量,而from_raw_parts技巧允许您在平台的字节顺序中“查看”字节向量作为u16的切片,这也可能是大端。如果您想要完全可移植性,那么使用像byteorder这样的包可能会有所帮助。

This关于Reddit的讨论也可能有所帮助。

答案 1 :(得分:2)

Rust 1.46+

对于静态 UTF-16 字符串,utf16_lit crate 提供了一个易于使用的宏来在编译时执行此操作:

use utf16_lit::utf16_null;

fn main() {
    let s = &utf16_null!("Hello");
    println!("{:?}", s);
}

答案 2 :(得分:0)

WinSafe 板条箱的 WString 类型正是为此目的:

let my_str = WString::from_str("Some text");

unsafe {
    SomeNativeFunctionW( my_str.as_ptr() );
}