Skip to content

Suggest using string.lines() when string.split("\n"), or string.split("\r\n") is seen #8733

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Closed
cowlicks opened this issue Apr 22, 2022 · 9 comments · Fixed by #11987
Closed
Assignees
Labels
A-lint Area: New lints good-first-issue These issues are a good way to get started with Clippy

Comments

@cowlicks
Copy link
Contributor

cowlicks commented Apr 22, 2022

What it does

Suggest replacing string.split("\n"), string.split('\n'), and string.split("\r\n") with string.lines().

Note that clippy throws a single_char_split warning for string.split("\n") which should be updated to this.

Lint Name

non_portable_line_iteration

Category

suspicious, style

Advantage

Makes string line iteration portable across Unix and Windows.

Drawbacks

If you need to differentiate between platform specific newlines this will be a false positive.
Also, if the string has a final terminating newline, the result of a .split will differ from .lines.
This could be avoiding by having the lint only trigger on .trim().split(sep).

Example

for line in string.split("\n") { ... }
// or
for line in string.split("\r\n") { ... }
// or
for line in string.split('\n') { ... }

Could be written as:

for line in string.lines() { ... }
@cowlicks cowlicks added the A-lint Area: New lints label Apr 22, 2022
@xFrednet xFrednet added the good-first-issue These issues are a good way to get started with Clippy label Apr 22, 2022
@ghost
Copy link

ghost commented Apr 22, 2022

It's not equivalent.

fn main() {
    let text = "foo\r\nbar\n\nbaz\n";
    println!("{:?}", text.split("\n").collect::<Vec<_>>());
    println!("{:?}", text.split("\r\n").collect::<Vec<_>>());
    println!("{:?}", text.lines().collect::<Vec<_>>());
}

gives

["foo\r", "bar", "", "baz", ""]
["foo", "bar\n\nbaz\n"]
["foo", "bar", "", "baz"]

Even when the line endings aren't mixed, lines doesn't include the empty element after the final \n.

@fedemartinezdev
Copy link
Contributor

@rustbot claim

@fedemartinezdev fedemartinezdev removed their assignment May 5, 2022
@yonip23
Copy link
Contributor

yonip23 commented May 5, 2022

@mikerite so what are you suggesting? Maybe this lint can go into the "pedantic" category, with an appropriate message stating that they're not equivalent, but maybe you can rewrite a bit in order to use the lines api?

@yonip23
Copy link
Contributor

yonip23 commented May 5, 2022

Also, if this lint is still not taken I'd like to claim it 🙂
(Not sure if / what exactly needs to be done yet, but anyway haha)

@ghost
Copy link

ghost commented May 6, 2022

I think this lint shouldn't exist or it should go into restriction.

The line endings and final blank element won't matter 99% of the time. When it does, the suggestion introduce bugs.

@joshuachp
Copy link

@rustbot claim

@joshuachp joshuachp removed their assignment Nov 25, 2023
@cowlicks
Copy link
Contributor Author

cowlicks commented Dec 8, 2023

It's not equivalent.

Indeed it is not. Good point about the final "", I'll update the issue. However I think in most cases where someone is doing this, they actually want what .lines() does, but they just don't know it exists. I think most users are not interested in the final "" you get from a case like "foo\nbar\n".split("\n"). Likewise I think in most cases the user is probably actually wants to handle "\r\n" too.

Perhaps a good middle ground would be to only suggest this lint whenever we see foo.trim().split(sep). If you can see from this search that there is a lot of code in the wild that does this.

@torfsen
Copy link
Contributor

torfsen commented Dec 17, 2023

@rustbot claim

@torfsen
Copy link
Contributor

torfsen commented Dec 19, 2023

Perhaps a good middle ground would be to only suggest this lint whenever we see foo.trim().split(sep). If you can see from this search that there is a lot of code in the wild that does this.

Just for my own records, right now the GitHub search finds

  • 1.4k files containing .trim.split('\n')
  • 832 files containing .trim.split("\n")
  • 9 files containing .trim.split("\r\n")

@bors bors closed this as completed in a89eb85 Dec 31, 2023
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
A-lint Area: New lints good-first-issue These issues are a good way to get started with Clippy
Projects
None yet
Development

Successfully merging a pull request may close this issue.

6 participants