259. str::lines — Split Into Lines Without Dragging \r Along
split('\n') works fine — until a Windows-saved file hands you lines that all end in an invisible \r. lines() was built for exactly this.
The trap
Same story as bite 258: split takes your separator literally. A file saved on Windows uses \r\n line endings, so every “line” keeps a carriage return — and the trailing newline produces a bonus empty string:
| |
That stray \r is invisible in most debug output, so it surfaces as "gamma" != "gamma" mysteries: failed comparisons, HashMap misses, parse errors on the last field.
The fix
lines() splits on \n and strips a trailing \r if one is there — so the same code handles Unix and Windows files:
| |
No trailing empty string either — like split_terminator (bite 233), the final newline is treated as a terminator, not a separator.
One caveat
Only \r\n and \n count as line endings. A lone \r (classic Mac OS, some protocol payloads) does not split:
| |
And a \r in the middle of a line stays untouched — only one directly before the \n is stripped.
Reading a file? BufRead::lines() gives you the same semantics over owned Strings. Either way: for “give me the lines”, it’s lines() every time — save split('\n') for when you truly mean raw bytes-between-newlines.