Как мне разбить строку в Rust?

145

Из документации не понятно. В Java вы можете использовать splitметод следующим образом:

"some string 123 ffd".split("123");
ア レ ッ ク ス
источник
@bow Есть ли способ сделать его массивом String вместо вектора?
Грег
Я не знаю ни одного способа сделать это, по крайней мере, напрямую. Возможно, вам придется вручную перебрать Splitи установить его в массив. Конечно, это означает, что количество элементов в каждом разбиении должно быть одинаковым, так как массивы имеют фиксированный размер, и вы должны иметь определенный ранее массив. Я полагаю, что это может быть больше проблем, чем просто создание Vec.
поклон

Ответы:

160

использование 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();
Manishearth
источник
15
Вы также можете написать это .collect::<Vec<_>>().
Крис Морган
как я могу получить длину результата - let split? split.len()не существует
ス レ ッ ク ス
5
@AlexanderSupertramp Use .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>

Разделить на символы:

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>.
JMB
источник
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<_>>();
Грег
6

Есть также split_whitespace()

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