Як розділити рядок у Rust?


143

З документації незрозуміло. У Java ви можете використовувати такий splitметод, як:

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


@bow Чи є спосіб зробити це масив String замість вектора?
Грег

Я не знаю жодного способу зробити це, принаймні, безпосередньо. Можливо, вам, мабуть, доведеться вручну перебирати Splitі встановлювати його в масив. Звичайно, це означає, що кількість елементів у кожному розділі має бути однаковою, оскільки масиви мають фіксований розмір, і ви повинні мати масив, визначений раніше. Я думаю, це може бути більше проблем, ніж просто створення Vec.
лук

Відповіді:


158

Використовуйте 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<_>>().
Кріс Морган

як мені отримати довжину результату - let split? split.len()не існує.
ア レ ッ ク ス

5
@AlexanderSupertramp Використання .count(). len()призначений лише для ітераторів, які знають їх точний розмір, не потребуючи вживання, count()споживає ітератор.
Manishearth

error: cannot borrow immutable local variable split` as mutable`
ア レ ッ ク ス

@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для структуриString :

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

Розділити за допомогою char:

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не припускає, що ви хочете зберегти результат. Ви можете використовувати a Vec, але ви також можете використовувати все, що реалізує FromIterator<&str>, наприклад, a LinkedListабо a 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
Грег

Однак він працює, як очікувалося, якщо я використовуюlet x = line.as_ref().unwrap().split(",").collect::<Vec<_>>();
Грег

Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.