Skip to content

Commit c4d2f61

Browse files
authored
Merge pull request #49 from JuliaString/spj/addcommas
Improve addcommas processing
2 parents b486b35 + 45eee87 commit c4d2f61

File tree

2 files changed

+39
-33
lines changed

2 files changed

+39
-33
lines changed

src/cformat.jl

Lines changed: 38 additions & 32 deletions
Original file line numberDiff line numberDiff line change
@@ -15,7 +15,8 @@ function generate_formatter( fmt::ASCIIStr )
1515

1616
if !occursin("'", fmt)
1717
checkfmt(fmt)
18-
return (formatters[ fmt ] = @eval(x->@sprintf( $fmt, x )))
18+
formatter = @eval(x->@sprintf( $fmt, x ))
19+
return (formatters[ fmt ] = x->Base.invokelatest(formatter, x))
1920
end
2021

2122
conversion = fmt[end]
@@ -24,60 +25,65 @@ function generate_formatter( fmt::ASCIIStr )
2425

2526
fmtactual = replace( fmt, "'" => ""; count=1 )
2627
checkfmt( fmtactual )
27-
conversion in "sfF" ||
28-
return (formatters[ fmt ] = @eval(x->checkcommas(@sprintf( $fmtactual, x ))))
29-
30-
formatters[ fmt ] =
31-
if endswith( fmtactual, 's')
28+
formatter =
29+
if !(conversion in "sfF")
30+
@eval(x->checkcommas(@sprintf( $fmtactual, x )))
31+
elseif endswith( fmtactual, 's')
3232
@eval((x::Real)->((eltype(x) <: Rational)
3333
? addcommasrat(@sprintf( $fmtactual, x ))
3434
: addcommasreal(@sprintf( $fmtactual, x ))))
3535
else
3636
@eval((x::Real)->addcommasreal(@sprintf( $fmtactual, x )))
3737
end
38+
return (formatters[ fmt ] = x->Base.invokelatest(formatter, x))
3839
end
3940

4041
function addcommasreal(s)
42+
len = length(s)
4143
dpos = findfirst( isequal('.'), s )
42-
dpos !== nothing && return string(addcommas( s[1:dpos-1] ), s[ dpos:end ])
44+
dpos !== nothing && return addcommas(s, len, dpos-1)
4345
# find the rightmost digit
44-
for i in length( s ):-1:1
45-
isdigit( s[i] ) && return string(addcommas( s[1:i] ), s[i+1:end])
46+
for i in len:-1:1
47+
isdigit( s[i] ) && return addcommas(s, len, i)
4648
end
4749
s
4850
end
4951

50-
function addcommasrat(s)
51-
# commas are added to only the numerator
52-
spos = findfirst( isequal('/'), s )
53-
string(addcommas( s[1:spos-1] ), s[spos:end])
54-
end
52+
# commas are added to only the numerator
53+
addcommasrat(s) = addcommas(s, length(s), findfirst( isequal('/'), s )-1)
5554

5655
function checkcommas(s)
57-
for i in length( s ):-1:1
58-
if isdigit( s[i] )
59-
s = string(addcommas( s[1:i] ), s[i+1:end])
60-
break
61-
end
56+
len = length(s)
57+
for i in len:-1:1
58+
isdigit( s[i] ) && return addcommas(s, len, i)
6259
end
6360
s
6461
end
6562

66-
function addcommas( s::ASCIIStr )
67-
len = length(s)
68-
t = ""
69-
for i in 1:3:len
70-
subs = s[max(1,len-i-1):len-i+1]
71-
if i == 1
72-
t = subs
73-
elseif match( r"[0-9]", subs ) != nothing
74-
t = string(subs, ',', t)
75-
else
76-
t = string(subs, t)
77-
end
63+
function addcommas(s::T, len, lst) where {T<:AbstractString}
64+
lst < 4 && return s
65+
beg = 1
66+
while beg < len
67+
isdigit(s[beg]) && break
68+
beg += 1
69+
end
70+
dig = lst - beg + 1
71+
dig < 4 && return s
72+
73+
commas = div(dig - 1, 3)
74+
sv = Base.StringVector(len + commas)
75+
76+
for i = 1:beg-1; sv[i] = s[i]; end
77+
cnt = dig - commas*3
78+
pos = beg - 1
79+
for i = beg:lst-3
80+
sv[pos += 1] = s[i]
81+
(cnt -= 1) == 0 && (cnt = 3; sv[pos += 1] = ',')
7882
end
79-
t
83+
for i = lst-2:len; sv[i+commas] = s[i]; end
84+
T(sv)
8085
end
86+
addcommas(s) = (l = length(s); addcommas(s, l, l))
8187

8288
function generate_format_string(;
8389
width::Int=-1,

src/fmt.jl

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -126,7 +126,7 @@ end
126126
function _optional_commas(x::Real, s::AbstractString, fspec::FormatSpec)
127127
prevwidth = length(s)
128128
dpos = findfirst( isequal('.'), s)
129-
s = dpos === nothing ? addcommas(s) : string(addcommas(s[1:dpos-1]), '.', s[dpos+1:end])
129+
s = addcommas(s, prevwidth, dpos === nothing ? prevwidth : dpos - 1)
130130

131131
# check for excess width from commas
132132
w = length(s)

0 commit comments

Comments
 (0)