str::split_inclusive¶
Level: reference · for working programmers
One line: Splits after each match, keeping the separator on the end of the piece it terminated.
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— discards the separatorstr::lines— discards it and normalizes\r\nstr::split_terminator— discards it but drops the trailing emptystr::matches— the separators on their own
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