Skip to content

str::split_inclusive

str methods · Strings

Level: reference · for working programmers

One line: Splits after each match, keeping the separator on the end of the piece it terminated.

pub fn split_inclusive<P: Pattern>(&self, pat: P) -> SplitInclusive<'_, P>

Stable since 1.51.0.

"a\nb\n".split_inclusive('\n') is ["a\n", "b\n"]. Nothing is thrown away, so concatenating the pieces reconstructs the original string exactly — which is what makes it the right tool for a streaming rewriter that must preserve line endings it does not understand.

Because the separator terminates a piece, there is no trailing empty: a string ending in the separator yields no extra item. A string not ending in the separator yields a final piece without one, which is how you tell a complete last line from a truncated one.

The empty string yields no pieces at all.

Example

str_split_inclusive.rs in full — pasted here by tools/run_examples.py from the file CI compiles and runs.

fn main() {
    for input in ["a\nb\n", "a\nb", "", "\n"] {
        println!("{:<8} -> {:?}", format!("{input:?}"), input.split_inclusive('\n').collect::<Vec<&str>>());
    }

    // Nothing is discarded, so the pieces rebuild the original.
    let text = "alpha\r\nbeta\ngamma";
    let pieces: Vec<&str> = text.split_inclusive('\n').collect();
    println!("{pieces:?}");
    println!("round trip: {}", pieces.concat() == text);

    // lines() would have thrown the endings away.
    println!("{:?}", text.lines().collect::<Vec<&str>>());

    // Telling a terminated last line from an unterminated one.
    for input in ["a\nb\n", "a\nb"] {
        let last = input.split_inclusive('\n').last().unwrap();
        println!("{:<8} last piece {last:?} terminated={}", format!("{input:?}"), last.ends_with('\n'));
    }
}

Verified output of str_split_inclusive.rs — regenerated by tools/run_examples.py, never hand-typed.

"a\nb\n" -> ["a\n", "b\n"]
"a\nb"   -> ["a\n", "b"]
""       -> []
"\n"     -> ["\n"]
["alpha\r\n", "beta\n", "gamma"]
round trip: true
["alpha", "beta", "gamma"]
"a\nb\n" last piece "b\n" terminated=true
"a\nb"   last piece "b" terminated=false

See also

str::split_inclusive in the standard library ↗

Po polsku

split_inclusive zostawia separator przyklejony do kawałka, który ten separator zakończył — "a\nb\n" daje ["a\n", "b\n"] — więc nic nie przepada i pieces.concat() odtwarza oryginał co do bajta. Ta własność ratuje skórę przy przepisywaniu plików: lines() końce wierszy wyrzuca i przy okazji normalizuje \r\n do \n, więc wczytanie przez lines() i sklejenie przez join("\n") po cichu zamienia windowsowe zakończenia na uniksowe, a git pokazuje potem zmianę w każdym wierszu pliku — dokładnie tę różnicę widać w przykładzie, gdzie ["alpha\r\n", "beta\n", "gamma"] stoi obok ["alpha", "beta", "gamma"]. Skoro separator kończy kawałek, nie ma tu żadnego pustego elementu na końcu, a ostatni kawałek bez separatora jest czytelnym sygnałem, że tekst urwał się bez znaku nowego wiersza (terminated=false). Uwaga na skrajny przypadek: pusty tekst nie daje tu ani jednego kawałka, w odróżnieniu od split, gdzie "" zwraca [""].

Szukaj po polsku: zachowanie końców wierszy CRLF · przepisywanie pliku bez zmiany znaków końca wiersza · rust split_inclusive keep separator · rust lines vs split_inclusive