From 1272653b6a9baae62929008c99f8946b8c095cde Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Bogumi=C5=82=20Kami=C5=84ski?= Date: Thu, 9 Nov 2017 21:54:12 +0100 Subject: [PATCH 1/4] allow nchar to be geater than string length in first/last without throwing an error --- base/strings/basic.jl | 19 ++++++++++++++----- test/strings/basic.jl | 35 ++++++++++++++++++----------------- 2 files changed, 32 insertions(+), 22 deletions(-) diff --git a/base/strings/basic.jl b/base/strings/basic.jl index 6dd8ffddc3566..91c146f44c74a 100644 --- a/base/strings/basic.jl +++ b/base/strings/basic.jl @@ -595,7 +595,7 @@ end """ first(str::AbstractString, nchar::Integer) -Get a string consisting of the first `nchar` characters of `str`. +Get a string consisting of at most the first `nchar` characters of `str`. ```jldoctest julia> first("∀ϵ≠0: ϵ²>0", 0) @@ -606,19 +606,24 @@ julia> first("∀ϵ≠0: ϵ²>0", 1) julia> first("∀ϵ≠0: ϵ²>0", 3) "∀ϵ≠" + +julia> first("1234", 10) +"1234" ``` """ function first(str::AbstractString, nchar::Integer) + s = start(str) if 0 <= nchar <= 1 - return str[1:nchar] + return str[s:(s-1+nchar)] end - str[1:nextind(str, 1, nchar-1)] + idx = min(endof(str), nextind(str, s, nchar-1)) + str[s:idx] end """ last(str::AbstractString, nchar::Integer) -Get a string consisting of the last `nchar` characters of `str`. +Get a string consisting of at most the last `nchar` characters of `str`. ```jldoctest julia> last("∀ϵ≠0: ϵ²>0", 0) @@ -629,6 +634,9 @@ julia> last("∀ϵ≠0: ϵ²>0", 1) julia> last("∀ϵ≠0: ϵ²>0", 3) "²>0" + +julia> last("1234", 10) +"1234" ``` """ function last(str::AbstractString, nchar::Integer) @@ -636,7 +644,8 @@ function last(str::AbstractString, nchar::Integer) if 0 <= nchar <= 1 return str[(e-nchar+1):e] end - str[prevind(str, e, nchar-1):e] + idx = max(start(str), prevind(str, e, nchar-1)) + str[idx:e] end # reverse-order iteration for strings and indices thereof diff --git a/test/strings/basic.jl b/test/strings/basic.jl index 17c1608bbee1f..63583ed115688 100644 --- a/test/strings/basic.jl +++ b/test/strings/basic.jl @@ -637,23 +637,24 @@ end end @testset "first and last" begin - s = "∀ϵ≠0: ϵ²>0" - @test_throws ArgumentError first(s, -1) - @test first(s, 0) == "" - @test first(s, 1) == "∀" - @test first(s, 2) == "∀ϵ" - @test first(s, 3) == "∀ϵ≠" - @test first(s, 4) == "∀ϵ≠0" - @test first(s, length(s)) == s - @test_throws BoundsError first(s, length(s)+1) - @test_throws ArgumentError last(s, -1) - @test last(s, 0) == "" - @test last(s, 1) == "0" - @test last(s, 2) == ">0" - @test last(s, 3) == "²>0" - @test last(s, 4) == "ϵ²>0" - @test last(s, length(s)) == s - @test_throws BoundsError last(s, length(s)+1) + let s = "∀ϵ≠0: ϵ²>0" + @test_throws ArgumentError first(s, -1) + @test first(s, 0) == "" + @test first(s, 1) == "∀" + @test first(s, 2) == "∀ϵ" + @test first(s, 3) == "∀ϵ≠" + @test first(s, 4) == "∀ϵ≠0" + @test first(s, length(s)) == s + @test first(s, length(s)+1) == s + @test_throws ArgumentError last(s, -1) + @test last(s, 0) == "" + @test last(s, 1) == "0" + @test last(s, 2) == ">0" + @test last(s, 3) == "²>0" + @test last(s, 4) == "ϵ²>0" + @test last(s, length(s)) == s + @test last(s, length(s)+1) == s + end end @testset "invalid code point" begin From 1792389517d6c68a0a6e34c6066de47f27b55ed6 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Bogumi=C5=82=20Kami=C5=84ski?= Date: Tue, 21 Nov 2017 23:32:12 +0100 Subject: [PATCH 2/4] correct behavior for empty strings and add more tests --- base/strings/basic.jl | 10 ++++------ test/strings/basic.jl | 12 +++++++++++- 2 files changed, 15 insertions(+), 7 deletions(-) diff --git a/base/strings/basic.jl b/base/strings/basic.jl index 91c146f44c74a..762d90a97fd8a 100644 --- a/base/strings/basic.jl +++ b/base/strings/basic.jl @@ -613,9 +613,8 @@ julia> first("1234", 10) """ function first(str::AbstractString, nchar::Integer) s = start(str) - if 0 <= nchar <= 1 - return str[s:(s-1+nchar)] - end + (nchar == 0 || isempty(str)) && return str[s:(s-1)] + nchar == 1 && return str[s:s] idx = min(endof(str), nextind(str, s, nchar-1)) str[s:idx] end @@ -641,9 +640,8 @@ julia> last("1234", 10) """ function last(str::AbstractString, nchar::Integer) e = endof(str) - if 0 <= nchar <= 1 - return str[(e-nchar+1):e] - end + (nchar == 0 || isempty(str)) && return str[e:(e-1)] + nchar == 1 && return str[e:e] idx = max(start(str), prevind(str, e, nchar-1)) str[idx:e] end diff --git a/test/strings/basic.jl b/test/strings/basic.jl index 63583ed115688..bf8e9a2386857 100644 --- a/test/strings/basic.jl +++ b/test/strings/basic.jl @@ -637,7 +637,7 @@ end end @testset "first and last" begin - let s = "∀ϵ≠0: ϵ²>0" + for s in ["∀ϵ≠0: ϵ²>0", s"∀ϵ≠0: ϵ²>0", SubString("∀ϵ≠0: ϵ²>0", 1)] @test_throws ArgumentError first(s, -1) @test first(s, 0) == "" @test first(s, 1) == "∀" @@ -655,6 +655,16 @@ end @test last(s, length(s)) == s @test last(s, length(s)+1) == s end + for s in ["", s"", SubString("", 1)] + @test_throws ArgumentError first(s, -1) + @test first(s, 0) == "" + @test first(s, 1) == "" + @test first(s, 2) == "" + @test_throws ArgumentError last(s, -1) + @test last(s, 0) == "" + @test last(s, 1) == "" + @test last(s, 2) == "" + end end @testset "invalid code point" begin From 93f56db2224c761033a31aa9374b8492cfc87faf Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Bogumi=C5=82=20Kami=C5=84ski?= Date: Wed, 22 Nov 2017 17:44:16 +0100 Subject: [PATCH 3/4] improve first/last docstring --- base/strings/basic.jl | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/base/strings/basic.jl b/base/strings/basic.jl index 762d90a97fd8a..922e43f8f9c35 100644 --- a/base/strings/basic.jl +++ b/base/strings/basic.jl @@ -595,7 +595,8 @@ end """ first(str::AbstractString, nchar::Integer) -Get a string consisting of at most the first `nchar` characters of `str`. +Get a string consisting of the first `nchar` characters of `str` unless `str` +is shorter than `nchar` characters, in which case a string equal to `str` is returned. ```jldoctest julia> first("∀ϵ≠0: ϵ²>0", 0) @@ -622,7 +623,8 @@ end """ last(str::AbstractString, nchar::Integer) -Get a string consisting of at most the last `nchar` characters of `str`. +Get a string consisting of the last `nchar` characters of `str` unless `str` +is shorter than `nchar` characters, in which case a string equal to `str` is returned. ```jldoctest julia> last("∀ϵ≠0: ϵ²>0", 0) From 6d6de2a7459641a7fa64501476386b487b5decba Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Bogumi=C5=82=20Kami=C5=84ski?= Date: Wed, 22 Nov 2017 17:52:02 +0100 Subject: [PATCH 4/4] fix corner case of empty string and negative nchar --- base/strings/basic.jl | 12 ++++++++++-- 1 file changed, 10 insertions(+), 2 deletions(-) diff --git a/base/strings/basic.jl b/base/strings/basic.jl index 922e43f8f9c35..a9cbb19484c22 100644 --- a/base/strings/basic.jl +++ b/base/strings/basic.jl @@ -614,7 +614,11 @@ julia> first("1234", 10) """ function first(str::AbstractString, nchar::Integer) s = start(str) - (nchar == 0 || isempty(str)) && return str[s:(s-1)] + nchar == 0 && return str[s:(s-1)] + if isempty(str) + nchar > 0 && return str[s:(s-1)] + throw(ArgumentError("nchar must be greater or equal than 0")) + end nchar == 1 && return str[s:s] idx = min(endof(str), nextind(str, s, nchar-1)) str[s:idx] @@ -642,7 +646,11 @@ julia> last("1234", 10) """ function last(str::AbstractString, nchar::Integer) e = endof(str) - (nchar == 0 || isempty(str)) && return str[e:(e-1)] + nchar == 0 && return str[e:(e-1)] + if isempty(str) + nchar > 0 && return str[e:(e-1)] + throw(ArgumentError("nchar must be greater or equal than 0")) + end nchar == 1 && return str[e:e] idx = max(start(str), prevind(str, e, nchar-1)) str[idx:e]