Wie teile ich eine Zeichenfolge in Rust?

142

Aus der Dokumentation geht nicht hervor. In Java können Sie die splitMethode folgendermaßen verwenden:

"some string 123 ffd".split("123");
ア レ ッ ク ス
quelle
@bow Gibt es eine Möglichkeit, ein String-Array anstelle eines Vektors zu erstellen?
Greg
Mir ist zumindest direkt keine Möglichkeit bekannt, dies zu tun. Sie müssten wahrscheinlich manuell über das iterieren Splitund es in das Array setzen. Dies bedeutet natürlich, dass die Anzahl der Elemente in jedem Split gleich sein muss, da Arrays eine feste Größe haben und das Array zuvor definiert werden muss. Ich stelle mir vor, dass dies mehr Probleme bereiten kann, als nur eine zu erstellen Vec.
Bogen

Antworten:

157

Verwenden split()

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

Dies ergibt einen Iterator, über den Sie eine Schleife oder collect()einen Vektor erstellen können.

for s in split {
    println!("{}", s)
}
let vec = split.collect::<Vec<&str>>();
// OR
let vec: Vec<&str> = split.collect();
Manishearth
quelle
15
Sie können es auch schreiben .collect::<Vec<_>>().
Chris Morgan
Wie bekomme ich die Länge des Ergebnisses - let split? split.len()existiert nicht.
ス レ ッ ク ス
5
@AlexanderSupertramp Verwendung .count(). len()ist nur für Iteratoren, die ihre genaue Größe kennen, ohne verbraucht werden zu müssen, count()verbraucht den Iterator.
Manishearth
error: cannot borrow immutable local variable split` as veränderlich`
ア レ ッ ク ス
@ AlexanderSupertramp let mut split, sorry.
Manishearth
52

Es gibt drei einfache Möglichkeiten:

  1. Durch Trennzeichen :

    s.split("separator")  |  s.split('/')  |  s.split(char::is_numeric)
  2. Mit Leerzeichen :

    s.split_whitespace()
  3. Durch Zeilenumbrüche :

    s.lines()

Das Ergebnis jeder Art ist ein Iterator:

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

Es gibt eine spezielle Methode splitfür structString :

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

Aufgeteilt nach Zeichen:

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

Geteilt nach Zeichenfolge:

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

Durch Verschluss geteilt:

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

splitgibt ein zurück Iterator, das Sie in ein Vecusing konvertieren können collect: split_line.collect::<Vec<_>>(). Das Durchlaufen eines Iterators anstelle der Vecdirekten Rückgabe eines hat mehrere Vorteile:

  • splitist faul. Dies bedeutet, dass die Linie erst dann wirklich geteilt wird, wenn Sie sie benötigen. Auf diese Weise wird keine Zeit damit verschwendet, die gesamte Zeichenfolge aufzuteilen, wenn Sie nur die ersten Werte benötigen: split_line.take(2).collect::<Vec<_>>()oder wenn Sie nur den ersten Wert benötigen, der in eine Ganzzahl konvertiert werden kann : split_line.filter_map(|x| x.parse::<i32>().ok()).next(). Dieses letzte Beispiel verschwendet keine Zeit mit dem Versuch, die "23.0" zu verarbeiten, sondern beendet die Verarbeitung sofort, sobald die "1" gefunden wird.
  • splitmacht keine Annahme darüber, wie Sie das Ergebnis speichern möchten. Sie können a verwenden Vec, aber Sie können auch alles verwenden, was implementiert wird FromIterator<&str>, z. B. a LinkedListoder a VecDeque, oder einen beliebigen benutzerdefinierten Typ, der implementiert wird FromIterator<&str>.
Jmb
quelle
1
Vielen Dank für Ihre ausführliche Antwort. Irgendwelche Ideen, warum let x = line.unwrap().split(",").collect::<Vec<_>>();funktioniert das nicht, wenn es nicht in zwei separate Zeilen unterteilt ist: let x = line.unwrap();und let x = x.split(",").collect::<Vec<_>>();? Die Fehlermeldung sagt:temporary value created here ^ temporary value dropped here while still borrowed
Greg
Es funktioniert jedoch wie erwartet, wenn ich benutzelet x = line.as_ref().unwrap().split(",").collect::<Vec<_>>();
Greg
6

Es gibt auch split_whitespace()

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