¿Cómo divido una cadena en Rust?

145

De la documentación , no está claro. En Java podría usar el splitmétodo de esta manera:

"some string 123 ffd".split("123");
ア レ ッ ク ス
fuente
@bow ¿Hay alguna manera de convertirlo en una matriz de cadenas en lugar de un vector?
Greg
No conozco ninguna forma de hacerlo, al menos directamente. Probablemente tendría que iterar manualmente sobre el Splity configurarlo en la matriz. Por supuesto, esto significa que el número de elementos en cada división debe ser el mismo, ya que las matrices tienen un tamaño fijo y debe tener la matriz definida anteriormente. Me imagino que esto puede ser más problemático que simplemente crear un Vec.
reverencia el

Respuestas:

160

Utilizar split()

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

Esto le da un iterador, que puede recorrer o collect()en un vector.

for s in split {
    println!("{}", s)
}
let vec = split.collect::<Vec<&str>>();
// OR
let vec: Vec<&str> = split.collect();
Manishearth
fuente
15
También puedes escribirlo .collect::<Vec<_>>().
Chris Morgan
¿Cómo obtengo la longitud del resultado let split? split.len()no existe
ア レ ッ ク ス
55
@AlexanderSupertramp Use .count(). len()es solo para iteradores que conocen su tamaño exacto sin necesidad de ser consumidos, count()consume el iterador.
Manishearth
error: cannot borrow immutable local variable split` as mutable`
ア レ ッ ク ス
@AlexanderSupertramp let mut split, lo siento.
Manishearth
53

Hay tres formas simples:

  1. Por separador :

    s.split("separator")  |  s.split('/')  |  s.split(char::is_numeric)
  2. Por espacios en blanco :

    s.split_whitespace()
  3. Por nuevas líneas :

    s.lines()

El resultado de cada tipo es un 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
fuente
29

Hay un método especial splitpara structString :

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

Dividido por char:

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

Dividir por cadena:

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

Dividir por cierre:

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

splitdevuelve una Iterator, que se puede convertir en un Vecusando collect: split_line.collect::<Vec<_>>(). Pasar por un iterador en lugar de devolver un Vecdirectamente tiene varias ventajas:

  • splites perezoso. Esto significa que realmente no dividirá la línea hasta que la necesite. De esa manera no va a perder el tiempo de la división toda la cadena si sólo necesita los primeros valores: split_line.take(2).collect::<Vec<_>>(), o incluso si sólo necesita el primer valor que se puede convertir en un entero: split_line.filter_map(|x| x.parse::<i32>().ok()).next(). Este último ejemplo no perderá tiempo intentando procesar el "23.0" pero detendrá el procesamiento inmediatamente una vez que encuentre el "1".
  • splitno asume la forma en que desea almacenar el resultado. Puede usar a Vec, pero también puede usar cualquier cosa que implemente FromIterator<&str>, por ejemplo a LinkedListo a VecDeque, o cualquier tipo personalizado que implemente FromIterator<&str>.
Jmb
fuente
1
Gracias por su respuesta detallada, alguna idea de por qué let x = line.unwrap().split(",").collect::<Vec<_>>();no funciona a menos que esté separada en dos líneas separadas: let x = line.unwrap();y let x = x.split(",").collect::<Vec<_>>();? El mensaje de error dice:temporary value created here ^ temporary value dropped here while still borrowed
Greg
Sin embargo, funciona como se espera si usolet x = line.as_ref().unwrap().split(",").collect::<Vec<_>>();
Greg
6

También hay split_whitespace()

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