Skip to content

Commit

Permalink
Implement @dec_str
Browse files Browse the repository at this point in the history
Fixes #26:
```julia
julia> dec"10_000.000_000_1"
10000.0000001
```
  • Loading branch information
barucden committed Oct 21, 2024
1 parent b2b8412 commit 91fff34
Show file tree
Hide file tree
Showing 4 changed files with 51 additions and 3 deletions.
10 changes: 9 additions & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -56,7 +56,15 @@ julia> parse(Decimal, x)
julia> tryparse(Decimal, x)
0.2
```
Parsing support scientific notation.
Parsing support scientific notation. Alternatively, you can use the `@dec_str`
macro, which also supports the thousands separator `_`:
```julia
julia> dec"0.2"
0.2

julia> dec"1_000.000_001"
1000.000001
```

### Conversion

Expand Down
3 changes: 2 additions & 1 deletion src/Decimals.jl
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,8 @@ module Decimals

export Decimal,
number,
normalize
normalize,
@dec_str

const DIGITS = 20

Expand Down
29 changes: 28 additions & 1 deletion src/parse.jl
Original file line number Diff line number Diff line change
@@ -1,3 +1,31 @@
macro dec_str(s)
# Taken from @big_str in Base
msg = "Invalid decimal: $s"
throw_error = :(throw(ArgumentError($msg)))

if '_' in s
# remove _ in s[2:end-1]
bf = IOBuffer(maxsize=lastindex(s))
c = s[1]
print(bf, c)
is_prev_underscore = (c == '_')
is_prev_dot = (c == '.')
for c in SubString(s, 2, lastindex(s) - 1)
c != '_' && print(bf, c)
c == '_' && is_prev_dot && return throw_error
c == '.' && is_prev_underscore && return throw_error
is_prev_underscore = (c == '_')
is_prev_dot = (c == '.')
end
print(bf, s[end])
s = String(take!(bf))
end

x = tryparse(Decimal, s)
x === nothing || return x
return throw_error
end

function Base.tryparse(::Type{Decimal}, str::AbstractString)
regex = Regex(string(
"^",
Expand Down Expand Up @@ -44,4 +72,3 @@ function Base.parse(::Type{Decimal}, str::AbstractString)
isnothing(x) && throw(ArgumentError("Invalid decimal: $str"))
return x
end

12 changes: 12 additions & 0 deletions test/test_parse.jl
Original file line number Diff line number Diff line change
Expand Up @@ -27,4 +27,16 @@
@test isnothing(tryparse(Decimal, "1e1e1"))
@test isnothing(tryparse(Decimal, "1-1"))
end

@testset "@dec_str" begin
@test dec"1.123" == Decimal(0, 1123, -3)
@test dec"-1.123" == Decimal(1, 1123, -3)
@test dec"123" == Decimal(0, 123, 0)
@test dec"-123" == Decimal(1, 123, 0)
@test dec"1_000.002" == Decimal(0, 1000002, -3)
@test dec"1_000_000.002" == Decimal(0, 1000000002, -3)

@test_throws ArgumentError dec"100_"
@test_throws ArgumentError dec"100_.0"
end
end

0 comments on commit 91fff34

Please sign in to comment.