Skip to content
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

RFC: make countlines count final non-empty line even without EOL #25845

Merged
merged 1 commit into from
Feb 1, 2018
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
5 changes: 4 additions & 1 deletion NEWS.md
Original file line number Diff line number Diff line change
Expand Up @@ -199,6 +199,9 @@ This section lists changes that do not have deprecation warnings.
* `readuntil` now does *not* include the delimiter in its result, matching the
behavior of `readline`. Pass `keep=true` to get the old behavior ([#25633]).

* `countlines` now always counts the last non-empty line even if it does not
end with EOL, matching the behavior of `eachline` and `readlines` ([#25845]).

* `getindex(s::String, r::UnitRange{Int})` now throws `UnicodeError` if `last(r)`
is not a valid index into `s` ([#22572]).

Expand Down Expand Up @@ -1260,4 +1263,4 @@ Command-line option changes
[#25622]: https://github.com/JuliaLang/julia/issues/25622
[#25634]: https://github.com/JuliaLang/julia/issues/25634
[#25654]: https://github.com/JuliaLang/julia/issues/25654
[#25655]: https://github.com/JuliaLang/julia/issues/25655
[#25655]: https://github.com/JuliaLang/julia/issues/25655
10 changes: 7 additions & 3 deletions base/io.jl
Original file line number Diff line number Diff line change
Expand Up @@ -999,7 +999,8 @@ end

Read `io` until the end of the stream/file and count the number of lines. To specify a file
pass the filename as the first argument. EOL markers other than `'\\n'` are supported by
passing them as the second argument.
passing them as the second argument. The last non-empty line of `io` is counted even if it does not
end with the EOL, matching the length returned by [`eachline`](@ref) and [`readlines`](@ref).

# Examples
```jldoctest
Expand All @@ -1011,7 +1012,7 @@ julia> countlines(io)
julia> io = IOBuffer("JuliaLang is a GitHub organization.");

julia> countlines(io)
0
1

julia> countlines(io, eol = '.')
1
Expand All @@ -1021,13 +1022,16 @@ function countlines(io::IO; eol::Char='\n')
isascii(eol) || throw(ArgumentError("only ASCII line terminators are supported"))
aeol = UInt8(eol)
a = Vector{UInt8}(uninitialized, 8192)
nl = 0
nl = nb = 0
while !eof(io)
nb = readbytes!(io, a)
@simd for i=1:nb
@inbounds nl += a[i] == aeol
end
end
if nb > 0 && a[nb] != aeol
nl += 1 # final line is not terminated with eol
end
nl
end

Expand Down
7 changes: 5 additions & 2 deletions test/read.jl
Original file line number Diff line number Diff line change
Expand Up @@ -537,15 +537,18 @@ rm(f)
end # mktempdir() do dir

@testset "countlines" begin
@test countlines(IOBuffer("")) == 0
@test countlines(IOBuffer("\n")) == 1
@test countlines(IOBuffer("\n"), eol = '\r') == 0
@test countlines(IOBuffer("\n"), eol = '\r') == 1
@test countlines(IOBuffer("\r\r\n\r"), eol = '\r') == 3
@test countlines(IOBuffer("\n\n\n\n\n\n\n\n\n\n")) == 10
@test countlines(IOBuffer("\n \n \n \n \n \n \n \n \n \n")) == 10
@test countlines(IOBuffer("\r\n \r\n \r\n \r\n \r\n")) == 5
@test countlines(IOBuffer("foo\nbar")) == length(readlines(IOBuffer("foo\nbar"))) == 2
file = tempname()
write(file,"Spiffy header\nspectacular first row\neven better 2nd row\nalmost done\n")
@test countlines(file) == 4
@test countlines(file, eol = '\r') == 0
@test countlines(file, eol = '\r') == 1
@test countlines(file, eol = '\n') == 4
rm(file)
end
Expand Down