ฉันจะแปลงเวกเตอร์ไบต์ (u8) เป็นสตริงได้อย่างไร


106

ฉันพยายามเขียนไคลเอนต์ TCP / IP อย่างง่ายใน Rust และฉันต้องการพิมพ์บัฟเฟอร์ที่ได้รับจากเซิร์ฟเวอร์

ฉันจะแปลง a Vec<u8>(หรือ a &[u8]) เป็น a ได้Stringอย่างไร

คำตอบ:


108

ในการแปลงชิ้นส่วนไบต์เป็นชิ้นสตริง (สมมติว่าเป็นการเข้ารหัส UTF-8):

use std::str;

//
// pub fn from_utf8(v: &[u8]) -> Result<&str, Utf8Error>
//
// Assuming buf: &[u8]
//

fn main() {

    let buf = &[0x41u8, 0x41u8, 0x42u8];

    let s = match str::from_utf8(buf) {
        Ok(v) => v,
        Err(e) => panic!("Invalid UTF-8 sequence: {}", e),
    };

    println!("result: {}", s);
}

การแปลงอยู่ในสถานที่และไม่จำเป็นต้องมีการจัดสรร คุณสามารถสร้างStringจากสไลซ์สตริงได้หากจำเป็นโดยเรียก.to_owned()ใช้สไลซ์สตริง ( มีตัวเลือกอื่น ๆ )

การอ้างอิงไลบรารีสำหรับฟังก์ชันการแปลง:


คุณอาจต้องการเพิ่มว่าสิ่งนี้เป็นไปได้เพราะ Vec บังคับให้หั่นชิ้น
torkleyy

แม้ว่าโค้ดตัวอย่างจะไม่ได้ใช้ Vector :-)
Andrew Mackenzie

แม้ว่าจะเป็นเรื่องจริงที่from_utf8ไม่ได้จัดสรร แต่ก็อาจคุ้มค่าที่จะกล่าวถึงว่าจำเป็นต้องสแกนข้อมูลเพื่อตรวจสอบความถูกต้องของ utf-8 ดังนั้นนี่ไม่ใช่การดำเนินการ O (1) (ซึ่งอาจคิดในตอนแรก)
Zargony

71

ฉันชอบString::from_utf8_lossy:

fn main() {
    let buf = &[0x41u8, 0x41u8, 0x42u8];
    let s = String::from_utf8_lossy(buf);
    println!("result: {}", s);
}

มันเปลี่ยน UTF-8 ไบต์ที่ไม่ถูกต้องเป็น ดังนั้นจึงไม่จำเป็นต้องจัดการข้อผิดพลาด มันดีสำหรับเมื่อคุณไม่ต้องการสิ่งนั้นและฉันแทบไม่ต้องการมันเลย คุณจะได้รับStringจากสิ่งนี้จริงๆ ควรทำให้การพิมพ์สิ่งที่คุณได้รับจากเซิร์ฟเวอร์ง่ายขึ้นเล็กน้อย

บางครั้งคุณอาจต้องใช้into_owned()วิธีนี้เนื่องจากเป็นการลอกแบบเขียน


4
ขอบคุณมากสำหรับinto_owned()คำแนะนำ! นั่นคือสิ่งที่ฉันกำลังมองหา (สิ่งนี้ทำให้มันกลายเป็นค่าที่เหมาะสมStringซึ่งคุณสามารถส่งคืนเป็นค่าส่งคืนจากวิธีการเป็นต้น)
Per Lundberg

53

หากคุณมีเวกเตอร์ไบต์ ( Vec<u8>) จริงและต้องการแปลงเป็น a Stringวิธีที่มีประสิทธิภาพที่สุดคือการนำการจัดสรรกลับมาใช้ใหม่กับString::from_utf8:

fn main() {
    let bytes = vec![0x41, 0x42, 0x43];
    let s = String::from_utf8(bytes).expect("Found invalid UTF-8");
    println!("{}", s);
}

2
ขอบคุณ! เหตุใดอีกสองคำตอบจึงเพิกเฉยต่อคำถาม
Jehan

1
@Jehan เพราะคนทั่วไปไม่ค่อยเก่งในการถามคำถามโดยเฉพาะอย่างยิ่งเมื่อพวกเขายังใหม่กับภาษา Rust ทำให้เกิดความแตกต่างระหว่างอาร์เรย์ไลซ์และVecเอ แต่ผู้มาใหม่ไม่รู้ความแตกต่าง อย่าลืมโหวตคำถามและคำตอบทั้งหมดที่พิสูจน์ว่ามีประโยชน์
Shepmaster

โปรดทราบว่าตามที่ @Bjorn Tipling กล่าวไว้คุณสามารถใช้String::from_utf8_lossyแทนได้ที่นี่คุณไม่จำเป็นต้องโทร
James Ray

2
แก้ไข: โปรดทราบว่าตามที่ @Bjorn Tipling กล่าวไว้คุณอาจคิดว่าคุณสามารถใช้String::from_utf8_lossyแทนได้ที่นี่คุณไม่จำเป็นต้องใช้การexpectโทร แต่ข้อมูลที่ป้อนนั้นเป็นส่วนของ bytess ( &'a [u8]) OTOH ก็มีเช่นfrom_utf8_uncheckedกัน "ถ้าคุณแน่ใจว่าชิ้นไบต์ที่ถูกต้อง UTF-8 และคุณไม่ต้องการที่จะต้องเสียค่าใช้จ่ายของการแปลงที่มีเป็นรุ่นที่ไม่ปลอดภัยของฟังก์ชันนี้ [ from_utf8_lossy], from_utf8_uncheckedซึ่งมีพฤติกรรมเดียวกัน แต่ข้ามการตรวจสอบ "
James Ray

โปรดทราบว่าคุณสามารถใช้&vec_of_bytesเพื่อแปลงกลับเป็นส่วนของไบต์ตามที่แสดงในตัวอย่างของfrom_utf8_lossy. doc.rust-lang.org/std/string/…
James Ray
โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.