Bagaimana cara membagi string di Rust?

156

Dari dokumentasinya , tidak jelas. Di Java Anda bisa menggunakan splitmetode seperti ini:

"some string 123 ffd".split("123");
ア レ ッ ク ス
sumber
@ Bow Apakah ada cara untuk membuatnya menjadi array String daripada vektor?
Greg
Saya tidak mengetahui cara untuk melakukan itu, setidaknya secara langsung. Anda mungkin harus mengulang secara manual Splitdan mengaturnya ke dalam array. Tentu saja ini berarti jumlah item di setiap pemisahan harus sama karena array berukuran tetap dan Anda harus memiliki array yang ditentukan sebelumnya. Saya membayangkan ini mungkin lebih merepotkan daripada hanya membuat file Vec.
busur

Jawaban:

175

Menggunakan split()

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

Ini memberikan iterator, yang dapat Anda ulangi, atau collect()menjadi vektor.

for s in split {
    println!("{}", s)
}
let vec = split.collect::<Vec<&str>>();
// OR
let vec: Vec<&str> = split.collect();
Manishearth
sumber
15
Anda juga bisa menulisnya .collect::<Vec<_>>().
Chris Morgan
bagaimana cara mendapatkan panjang hasilnya - let split? split.len()tidak ada.
ア レ ッ ク ス
6
@AlexanderSupertramp Gunakan .count(). len()hanya untuk iterator yang mengetahui ukuran pastinya tanpa perlu dikonsumsi, count()menggunakan iterator.
Manishearth
error: cannot borrow immutable local variable split` sebagai bisa berubah`
ア レ ッ ク ス
@AlexanderSupertramp let mut split, maaf.
Manishearth
58

Ada tiga cara sederhana:

  1. Dengan pemisah :

    s.split("separator")  |  s.split('/')  |  s.split(char::is_numeric)
    
  2. Menurut spasi :

    s.split_whitespace()
    
  3. Dengan baris baru :

    s.lines()
    

Hasil dari setiap jenis adalah iterator:

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());
DenisKolodin
sumber
31

Ada metode khusus splituntuk structString :

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

Pisahkan menurut karakter:

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

Pisahkan dengan string:

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

Pisahkan dengan penutupan:

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

splitmengembalikan sebuah Iterator, yang Anda dapat mengkonversi menjadi Vecmenggunakan collect: split_line.collect::<Vec<_>>(). Menggunakan iterator alih-alih mengembalikan Veclangsung memiliki beberapa keuntungan:

  • splitmalas. Ini berarti bahwa itu tidak akan benar-benar memisahkan garis sampai Anda membutuhkannya. Dengan cara itu tidak akan membuang-buang waktu membelah seluruh string jika Anda hanya perlu beberapa nilai pertama: split_line.take(2).collect::<Vec<_>>(), atau bahkan jika Anda hanya perlu nilai pertama yang dapat dikonversi ke integer: split_line.filter_map(|x| x.parse::<i32>().ok()).next(). Contoh terakhir ini tidak akan membuang waktu untuk mencoba memproses "23.0" tetapi akan segera berhenti memproses setelah menemukan "1".
  • splittidak membuat asumsi tentang cara Anda ingin menyimpan hasilnya. Anda dapat menggunakan a Vec, tetapi Anda juga dapat menggunakan apa pun yang mengimplementasikan FromIterator<&str>, misalnya a LinkedListatau a VecDeque, atau jenis kustom apa pun yang diimplementasikan FromIterator<&str>.
Jmb
sumber
1
Terima kasih atas jawaban rinci Anda, ada gagasan mengapa let x = line.unwrap().split(",").collect::<Vec<_>>();tidak berfungsi kecuali dipisahkan menjadi dua baris terpisah: let x = line.unwrap();dan let x = x.split(",").collect::<Vec<_>>();? Pesan kesalahan mengatakan:temporary value created here ^ temporary value dropped here while still borrowed
Greg
Namun itu bekerja seperti yang diharapkan jika saya menggunakanlet x = line.as_ref().unwrap().split(",").collect::<Vec<_>>();
Greg
7

Ada juga split_whitespace()

fn main() {
    let words: Vec<&str> = "   foo   bar\t\nbaz   ".split_whitespace().collect();
    println!("{:?}", words);
    // ["foo", "bar", "baz"] 
}
jayelm
sumber