Skip to content

Commit

Permalink
lpad, rpad: use character cound instead of textwidth [fix #25016]
Browse files Browse the repository at this point in the history
The general principle here is that we should avoid having behavior
in Base that depends on which version of Unicode you're using. It's
fine for an external package to provide versions of lpad and rpad
which use textwidth and thereby depend on Unicode details, but the
functions in Base should not depend on these.
  • Loading branch information
StefanKarpinski committed Dec 14, 2017
1 parent 8de25f5 commit 621bd19
Show file tree
Hide file tree
Showing 3 changed files with 80 additions and 30 deletions.
4 changes: 4 additions & 0 deletions base/deprecated.jl
Original file line number Diff line number Diff line change
Expand Up @@ -2996,6 +2996,10 @@ end
@deprecate ind2chr(s::AbstractString, i::Integer) length(s, 1, i)
@deprecate chr2ind(s::AbstractString, n::Integer) nextind(s, 0, n)

# issue #25016
@deprecate lpad(s, n::Integer, p=" ") lpad(string(s), n, string(p))
@deprecate rpad(s, n::Integer, p=" ") rpad(string(s), n, string(p))

# END 0.7 deprecations

# BEGIN 1.0 deprecations
Expand Down
66 changes: 40 additions & 26 deletions base/strings/util.jl
Original file line number Diff line number Diff line change
Expand Up @@ -204,49 +204,63 @@ strip(s::AbstractString, chars::Chars) = lstrip(rstrip(s, chars), chars)

## string padding functions ##

function lpad(s::AbstractString, n::Integer, p::AbstractString=" ")
m = n - Unicode.textwidth(s)
m 0 && return s
l = Unicode.textwidth(p)
q, r = divrem(m, l)
string(p^q, first(p, r), s)
end

function rpad(s::AbstractString, n::Integer, p::AbstractString=" ")
m = n - Unicode.textwidth(s)
m 0 && return s
l = Unicode.textwidth(p)
q, r = divrem(m, l)
string(s, p^q, first(p, r))
end

"""
lpad(s, n::Integer, p::AbstractString=" ")
lpad(
s::Union{Char,AbstractString},
n::Integer,
p::Union{Char,AbstractString} = ' ',
) -> AbstractString
Make a string at least `n` columns wide when printed by padding `s` on the left
with copies of `p`.
Pad `s` on the left with `p` to make it `n` characters (code points) long. If
`s` is already `n` characters long, an equal string is returned. Pad with spaces
by default.
# Examples
```jldoctest
julia> lpad("March",10)
julia> lpad("March", 10)
" March"
```
"""
lpad(s, n::Integer, p=" ") = lpad(string(s),n,string(p))
function lpad(
s::Union{Char,AbstractString},
n::Integer,
p::Union{Char,AbstractString} = ' ',
) :: String
m = n - length(s)
m 0 && return s
l = length(p)
q, r = divrem(m, l)
r == 0 ? string(p^q, s) : string(p^q, first(p, r), s)
end

"""
rpad(s, n::Integer, p::AbstractString=" ")
rpad(
s::Union{Char,AbstractString},
n::Integer,
p::Union{Char,AbstractString} = ' ',
) -> AbstractString
Make a string at least `n` columns wide when printed by padding `s` on the right
with copies of `p`.
Pad `s` on the right with `p` to make it `n` characters (code points) long. If
`s` is already `n` characters long, an equal string is returned. Pad with spaces
by default.
# Examples
```jldoctest
julia> rpad("March",20)
julia> rpad("March", 20)
"March "
```
"""
rpad(s, n::Integer, p=" ") = rpad(string(s),n,string(p))
function rpad(
s::Union{Char,AbstractString},
n::Integer,
p::Union{Char,AbstractString} = ' ',
) :: String
m = n - length(s)
m 0 && return s
l = length(p)
q, r = divrem(m, l)
r == 0 ? string(s, p^q) : string(s, p^q, first(p, r))
end

# splitter can be a Char, Vector{Char}, AbstractString, Regex, ...
# any splitter that provides search(s::AbstractString, splitter)
Expand Down
40 changes: 36 additions & 4 deletions test/strings/util.jl
Original file line number Diff line number Diff line change
@@ -1,14 +1,46 @@
# This file is a part of Julia. License is MIT: https://julialang.org/license

@testset "padding (lpad and rpad)" begin
@test lpad("foo", 2) == "foo"
@test rpad("foo", 2) == "foo"
@test lpad("foo", 3) == "foo"
@test rpad("foo", 3) == "foo"
@test lpad("foo", 4) == " foo"
@test rpad("foo", 4) == "foo "
@test lpad("foo", 5) == " foo"
@test rpad("foo", 5) == "foo "
@test lpad("foo", 5, " ") == " foo"
@test rpad("foo", 5, " ") == "foo "
@test lpad("foo", 6, " ") == " foo"
@test rpad("foo", 6, " ") == "foo "
@test lpad("foo", 2, "123") == "foo"
@test rpad("foo", 2, "123") == "foo"
@test lpad("foo", 3, "123") == "foo"
@test rpad("foo", 3, "123") == "foo"
@test lpad("foo", 4, "123") == "1foo"
@test rpad("foo", 4, "123") == "foo1"
@test lpad("foo", 5, "123") == "12foo"
@test rpad("foo", 5, "123") == "foo12"
@test lpad("foo", 6, "123") == "123foo"
@test rpad("foo", 6, "123") == "foo123"
@test lpad("foo", 7, "123") == "1231foo"
@test rpad("foo", 7, "123") == "foo1231"
@test lpad("foo", 8, "123") == "12312foo"
@test rpad("foo", 8, "123") == "foo12312"
@test lpad("foo", 9, "123") == "123123foo"
@test rpad("foo", 9, "123") == "foo123123"
@test lpad("αβ", 2, "¹₂³") == "αβ"
@test rpad("αβ", 2, "¹₂³") == "αβ"
@test lpad("αβ", 3, "¹₂³") == "¹αβ"
@test rpad("αβ", 3, "¹₂³") == "αβ¹"
@test lpad("αβ", 4, "¹₂³") == "¹₂αβ"
@test rpad("αβ", 4, "¹₂³") == "αβ¹₂"
@test lpad("αβ", 5, "¹₂³") == "¹₂³αβ"
@test rpad("αβ", 5, "¹₂³") == "αβ¹₂³"
@test lpad("αβ", 6, "¹₂³") == "¹₂³¹αβ"
@test rpad("αβ", 6, "¹₂³") == "αβ¹₂³¹"
@test lpad("αβ", 7, "¹₂³") == "¹₂³¹₂αβ"
@test rpad("αβ", 7, "¹₂³") == "αβ¹₂³¹₂"
@test lpad("αβ", 8, "¹₂³") == "¹₂³¹₂³αβ"
@test rpad("αβ", 8, "¹₂³") == "αβ¹₂³¹₂³"
@test lpad("αβ", 9, "¹₂³") == "¹₂³¹₂³¹αβ"
@test rpad("αβ", 9, "¹₂³") == "αβ¹₂³¹₂³¹"
end

# string manipulation
Expand Down

0 comments on commit 621bd19

Please sign in to comment.