Comment diviser une chaîne dans Rust?


145

D'après la documentation , ce n'est pas clair. En Java, vous pouvez utiliser la splitméthode comme ceci:

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


@bow Existe-t-il un moyen d'en faire un tableau de chaînes au lieu d'un vecteur?
Greg

Je ne connais aucun moyen de le faire, du moins directement. Vous devrez probablement parcourir manuellement le Splitet le définir dans le tableau. Bien sûr, cela signifie que le nombre d'éléments dans chaque division doit être le même puisque les tableaux sont de taille fixe et que vous devez avoir défini le tableau avant. J'imagine que cela peut être plus difficile que de simplement créer un fichier Vec.
archet

Réponses:


160

Utilisation split()

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

Cela donne un itérateur sur lequel vous pouvez faire une boucle ou collect()dans un vecteur.

for s in split {
    println!("{}", s)
}
let vec = split.collect::<Vec<&str>>();
// OR
let vec: Vec<&str> = split.collect();

15
Vous pouvez également l'écrire .collect::<Vec<_>>().
Chris Morgan

comment obtenir la longueur du résultat - let split? split.len()n'existe pas.
ア レ ッ ク ス

5
@AlexanderSupertramp Utilisation .count(). len()est uniquement pour les itérateurs qui connaissent leur taille exacte sans avoir besoin d'être consommés, count()consomme l'itérateur.
Manishearth

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

@AlexanderSupertramp let mut split, désolé.
Manishearth

53

Il existe trois moyens simples:

  1. Par séparateur :

    s.split("separator")  |  s.split('/')  |  s.split(char::is_numeric)
  2. Par espace :

    s.split_whitespace()
  3. Par nouvelles lignes :

    s.lines()

Le résultat de chaque type est un itérateur:

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

Il existe une méthode spéciale splitpour structString :

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

Divisé par caractère:

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

Split par chaîne:

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

Fractionnement par fermeture:

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

14

splitretourne un Iterator, que vous pouvez convertir en Vecutilisant collect: split_line.collect::<Vec<_>>(). Passer par un itérateur au lieu de renvoyer Vecdirectement un a plusieurs avantages:

  • splitest paresseux. Cela signifie qu'il ne divisera pas vraiment la ligne tant que vous n'en aurez pas besoin. De cette façon, vous ne perdrez pas de temps à diviser la chaîne entière si vous n'avez besoin que des premières valeurs:, split_line.take(2).collect::<Vec<_>>()ou même si vous n'avez besoin que de la première valeur qui peut être convertie en entier:split_line.filter_map(|x| x.parse::<i32>().ok()).next() . Ce dernier exemple ne perdra pas de temps à essayer de traiter le "23.0" mais arrêtera le traitement immédiatement une fois qu'il aura trouvé le "1".
  • splitne fait aucune hypothèse sur la manière dont vous souhaitez stocker le résultat. Vous pouvez utiliser a Vec, mais vous pouvez également utiliser tout ce qui implémente FromIterator<&str>, par exemple a LinkedListou a VecDeque, ou tout type personnalisé implémentant FromIterator<&str>.

1
Merci pour votre réponse détaillée, toute idée pourquoi let x = line.unwrap().split(",").collect::<Vec<_>>();ne fonctionne pas à moins qu'elle ne soit séparée en deux lignes distinctes: let x = line.unwrap();et let x = x.split(",").collect::<Vec<_>>();? Le message d'erreur dit:temporary value created here ^ temporary value dropped here while still borrowed
Greg

Cependant, cela fonctionne comme prévu si j'utiliselet x = line.as_ref().unwrap().split(",").collect::<Vec<_>>();
Greg

6

Il y a aussi split_whitespace()

fn main() {
    let words: Vec<&str> = "   foo   bar\t\nbaz   ".split_whitespace().collect();
    println!("{:?}", words);
    // ["foo", "bar", "baz"] 
}
En utilisant notre site, vous reconnaissez avoir lu et compris notre politique liée aux cookies et notre politique de confidentialité.
Licensed under cc by-sa 3.0 with attribution required.