diff --git a/NEWS.md b/NEWS.md index 3709fe8059b06..0a1ee0b1f77aa 100644 --- a/NEWS.md +++ b/NEWS.md @@ -252,8 +252,12 @@ This section lists changes that do not have deprecation warnings. Library improvements -------------------- + * Functions `first` and `last` now accept `nchar` argument for `AbstractString`. + If this argument is used they return a string consisting of first/last `nchar` + characters from the original string ([#23960]). + * The functions `nextind` and `prevind` now accept `nchar` argument that indicates - number of characters to move ([#23805]). + the number of characters to move ([#23805]). * The functions `strip`, `lstrip` and `rstrip` now return `SubString` ([#22496]). diff --git a/base/strings/basic.jl b/base/strings/basic.jl index b214fba344ecd..7eb36607d987d 100644 --- a/base/strings/basic.jl +++ b/base/strings/basic.jl @@ -611,3 +611,52 @@ function filter(f, s::AbstractString) end String(take!(out)) end + +## string first and last ## + +""" + first(str::AbstractString, nchar::Integer) + +Get a string consisting of the first `nchar` characters of `str`. + +```jldoctest +julia> first("∀ϵ≠0: ϵ²>0", 0) +"" + +julia> first("∀ϵ≠0: ϵ²>0", 1) +"∀" + +julia> first("∀ϵ≠0: ϵ²>0", 3) +"∀ϵ≠" +``` +""" +function first(str::AbstractString, nchar::Integer) + if 0 <= nchar <= 1 + return str[1:nchar] + end + str[1:nextind(str, 1, nchar-1)] +end + +""" + last(str::AbstractString, nchar::Integer) + +Get a string consisting of the last `nchar` characters of `str`. + +```jldoctest +julia> last("∀ϵ≠0: ϵ²>0", 0) +"" + +julia> last("∀ϵ≠0: ϵ²>0", 1) +"0" + +julia> last("∀ϵ≠0: ϵ²>0", 3) +"²>0" +``` +""" +function last(str::AbstractString, nchar::Integer) + e = endof(str) + if 0 <= nchar <= 1 + return str[(e-nchar+1):e] + end + str[prevind(str, e, nchar-1):e] +end diff --git a/doc/src/stdlib/strings.md b/doc/src/stdlib/strings.md index 9a40367f5f5ba..dca748eb40a2f 100644 --- a/doc/src/stdlib/strings.md +++ b/doc/src/stdlib/strings.md @@ -48,6 +48,8 @@ Base.lstrip Base.rstrip Base.startswith Base.endswith +Base.first(::AbstractString, ::Integer) +Base.last(::AbstractString, ::Integer) Base.uppercase Base.lowercase Base.titlecase diff --git a/test/strings/basic.jl b/test/strings/basic.jl index adaa472f713a0..13588b3d0be74 100644 --- a/test/strings/basic.jl +++ b/test/strings/basic.jl @@ -625,3 +625,23 @@ end @test prevind(strs[2], -1, 1) == 0 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) +end