ฉันจะแยกสตริงใน Rust ได้อย่างไร


144

จากเอกสารนั้นยังไม่ชัดเจน ใน Java คุณสามารถใช้splitวิธีการดังนี้:

"some string 123 ffd".split("123");


@bow มีวิธีทำให้อาร์เรย์เป็นสตริงแทนที่จะเป็นเวกเตอร์หรือไม่?
เกร็ก

อย่างน้อยฉันก็ไม่ทราบว่าจะทำเช่นนั้นโดยตรง คุณอาจจะต้องวนซ้ำมันด้วยตัวเองSplitและตั้งค่าลงในอาร์เรย์ แน่นอนนี่หมายความว่าจำนวนรายการในการแยกแต่ละครั้งจะต้องเท่ากันเนื่องจากอาร์เรย์มีขนาดคงที่และคุณต้องกำหนดอาร์เรย์ไว้ก่อน Vecผมคิดนี้อาจจะมีปัญหามากขึ้นกว่าเพียงแค่การสร้าง
คำนับ

คำตอบ:


159

ใช้ split()

let mut split = "some string 123 ffd".split("123");

สิ่งนี้จะให้ตัววนซ้ำซึ่งคุณสามารถวนซ้ำหรือcollect()เป็นเวกเตอร์

for s in split {
    println!("{}", s)
}
let vec = split.collect::<Vec<&str>>();
// OR
let vec: Vec<&str> = split.collect();

15
.collect::<Vec<_>>()นอกจากนี้คุณยังสามารถเขียนมัน
Chris Morgan

ฉันจะทราบความยาวของผลลัพธ์ได้let splitอย่างไร- split.len()ไม่มีอยู่
アレックス

5
@AlexanderSupertramp .count()ใช้ len()มีไว้สำหรับตัววนซ้ำที่รู้ขนาดที่แน่นอนของมันโดยไม่จำเป็นต้องcount()สิ้นเปลืองใช้ตัววนซ้ำ
Manishearth

error: cannot borrow immutable local variable แยก `ที่ไม่แน่นอน '
アレックス

@AlexanderSupertramp let mut splitขอโทษ
Manishearth

53

มีสามวิธีง่าย ๆ :

  1. โดยตัวแยก :

    s.split("separator")  |  s.split('/')  |  s.split(char::is_numeric)
  2. โดยช่องว่าง :

    s.split_whitespace()
  3. ตามบรรทัดใหม่ :

    s.lines()

ผลลัพธ์ของแต่ละชนิดคือตัววนซ้ำ:

let text = "foo\r\nbar\n\nbaz\n";
let mut lines = text.lines();

assert_eq!(Some("foo"), lines.next());
assert_eq!(Some("bar"), lines.next());
assert_eq!(Some(""), lines.next());
assert_eq!(Some("baz"), lines.next());

assert_eq!(None, lines.next());

29

มีวิธีพิเศษsplitสำหรับ structString :

fn split<'a, P>(&'a self, pat: P) -> Split<'a, P> where P: Pattern<'a>

แยกตามตัวอักษร:

let v: Vec<&str> = "Mary had a little lamb".split(' ').collect();
assert_eq!(v, ["Mary", "had", "a", "little", "lamb"]);

แยกตามสตริง:

let v: Vec<&str> = "lion::tiger::leopard".split("::").collect();
assert_eq!(v, ["lion", "tiger", "leopard"]);

แยกโดยปิด:

let v: Vec<&str> = "abc1def2ghi".split(|c: char| c.is_numeric()).collect();
assert_eq!(v, ["abc", "def", "ghi"]);

14

splitส่งคืนIteratorซึ่งคุณสามารถแปลงเป็นการVecใช้collect: split_line.collect::<Vec<_>>(). จะผ่านตัววนซ้ำแทนที่จะส่งกลับVecโดยตรงมีข้อดีหลายประการ:

  • splitขี้เกียจ ซึ่งหมายความว่าจะไม่แยกบรรทัดจนกว่าคุณต้องการ วิธีการที่จะไม่ต้องเสียเวลาในการแยกสตริงทั้งถ้าคุณต้องการเพียงค่าแรก: หรือแม้กระทั่งถ้าคุณต้องการเพียงค่าแรกที่สามารถแปลงเป็นจำนวนเต็ม:split_line.take(2).collect::<Vec<_>>() split_line.filter_map(|x| x.parse::<i32>().ok()).next()ตัวอย่างสุดท้ายนี้จะไม่เสียเวลาในการพยายามประมวลผล "23.0" แต่จะหยุดการประมวลผลทันทีเมื่อพบ "1"
  • splitทำให้ไม่มีการสันนิษฐานในแบบที่คุณต้องการเก็บผลลัพธ์ คุณสามารถใช้Vecแต่คุณยังสามารถใช้สิ่งที่นำไปปฏิบัติFromIterator<&str>ตัวอย่างเช่นLinkedListหรือVecDequeหรือประเภทที่กำหนดเองใด ๆ FromIterator<&str>ที่นำไปปฏิบัติ

1
ขอบคุณสำหรับคำตอบโดยละเอียดความคิดใด ๆ ที่let x = line.unwrap().split(",").collect::<Vec<_>>();ไม่ได้ผลเว้นแต่จะแยกออกเป็นสองบรรทัด: let x = line.unwrap();และlet x = x.split(",").collect::<Vec<_>>();? ข้อความแสดงข้อผิดพลาดแจ้งว่า:temporary value created here ^ temporary value dropped here while still borrowed
Greg

อย่างไรก็ตามมันใช้งานได้ตามที่คาดหวังถ้าฉันใช้let x = line.as_ref().unwrap().split(",").collect::<Vec<_>>();
Greg

โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.