Como faço para dividir uma string no Rust?

143

A partir da documentação , não está claro. Em Java, você pode usar o splitmétodo da seguinte maneira:

"some string 123 ffd".split("123");
ア レ ッ ク ス
fonte
@bow Existe uma maneira de torná-lo um array String em vez de um vetor?
7897 Greg
Não conheço nenhuma maneira de fazer isso, pelo menos diretamente. Você provavelmente teria que repetir manualmente Splite configurá-lo na matriz. Obviamente, isso significa que o número de itens em cada divisão deve ser o mesmo, pois as matrizes são de tamanho fixo e você deve ter a matriz definida antes. Eu imagino que isso possa ser mais problemático do que simplesmente criar um Vec.
arco

Respostas:

158

Usar split()

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

Isso fornece um iterador, no qual você pode fazer um loop ou collect()em um vetor.

for s in split {
    println!("{}", s)
}
let vec = split.collect::<Vec<&str>>();
// OR
let vec: Vec<&str> = split.collect();
Manishearth
fonte
15
Você também pode escrever .collect::<Vec<_>>().
Chris Morgan
como obtenho a duração do resultado - let split? split.len()não existe.
アレックス
5
@AlexanderSupertramp Use .count(). len()é apenas para iteradores que sabem seu tamanho exato sem precisar ser consumidos, count()consome o iterador.
Manishearth
error: cannot borrow immutable local variable split` como mutable`
アレックス
@AlexanderSupertramp let mut split, desculpe.
Manishearth
53

Existem três maneiras simples:

  1. Pelo separador :

    s.split("separator")  |  s.split('/')  |  s.split(char::is_numeric)
  2. Por espaço em branco :

    s.split_whitespace()
  3. Por novas linhas :

    s.lines()

O resultado de cada tipo é um iterador:

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
fonte
29

Existe um método especial splitpara structString :

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

Dividido por caracteres:

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

Dividido por sequência:

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

Dividir por fechamento:

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

splitretorna uma Iterator, que você pode converter em um Vecusando collect: split_line.collect::<Vec<_>>(). Passar por um iterador em vez de retornar um Vecdiretamente tem várias vantagens:

  • splité preguiçoso. Isso significa que ele realmente não vai dividir a linha até que você precise. Dessa forma, ele não vai perder divisão tempo todo a corda se você só precisa os primeiros valores: split_line.take(2).collect::<Vec<_>>()ou mesmo se você precisar apenas o primeiro valor que pode ser convertido para um inteiro: split_line.filter_map(|x| x.parse::<i32>().ok()).next(). Este último exemplo não perderá tempo tentando processar o "23.0", mas interromperá o processamento imediatamente quando encontrar o "1".
  • splitnão assume como você deseja armazenar o resultado. Você pode usar a Vec, mas também pode usar qualquer coisa que implemente FromIterator<&str>, por exemplo, a LinkedListou a VecDeque, ou qualquer tipo personalizado que implemente FromIterator<&str>.
Jmb
fonte
1
Obrigado pela resposta detalhada, alguma idéia de por let x = line.unwrap().split(",").collect::<Vec<_>>();que não funciona, a menos que seja separada em duas linhas separadas: let x = line.unwrap();e let x = x.split(",").collect::<Vec<_>>();? A mensagem de erro diz:temporary value created here ^ temporary value dropped here while still borrowed
Greg
No entanto, funciona como esperado se eu usarlet x = line.as_ref().unwrap().split(",").collect::<Vec<_>>();
Greg
6

Há também split_whitespace()

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