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");
ア レ ッ ク ス
la source
@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();
Manishearth
la source
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());
DenisKolodin
la source
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"]);
Denis Kreshikhin
la source
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>.
Jmb
la source
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"] 
}
Jayelm
la source