Skip to content

Commit

Permalink
modified: README.md Add 'parse' example, quantities from text files
Browse files Browse the repository at this point in the history
modified:   src/MechanicalUnits.jl Add 'parse'
new file:   src/parse.jl  New file
modified:   test/conversion_promotion.jl Add 'parse' tests
  • Loading branch information
hustf committed Nov 8, 2020
1 parent 71f73de commit d349c0f
Show file tree
Hide file tree
Showing 4 changed files with 93 additions and 1 deletion.
18 changes: 18 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -186,6 +186,24 @@ Unitfu.FreeUnits{(dyn,), ᴸ∙ ᴹ∙ ᵀ⁻²,nothing}

julia> 1dyn |> μm
10kgμms⁻²

julia> # When parsing text file, spaces as multipliers and brackets are allowed. Just specify the numeric type:
julia> lin = "2 [s]\t11364.56982421875 [N]\t-44553.50244140625 [N]\t-26.586366176605225 [N]\t0.0[N mm]\t0.0[N mm]\t0.0[N mm]\t1561.00350618362 [mm]\t-6072.3729133606 [mm]\t2825.15907287598 [mm]"
"2 [s]\t11364.56982421875 [N]\t-44553.50244140625 [N]\t-26.586366176605225 [N]\t0.0[N mm]\t0.0[N mm]\t0.0[N mm]\t1561.00350618362 [mm]\t-6072.3729133606 [mm]\t2825.15907287598 [mm]"

julia> time, Fx, Fy, Fz, Mx, My, Mz, px, py, pz = parse.(Quantity{Float64}, split(lin, '\t'))
10-element Array{Quantity{Float64,D,U} where U where D,1}:
2.0s
11364.56982421875N
-44553.50244140625N
-26.586366176605225N
0.0mmN
0.0mmN
0.0mmN
1561.00350618362mm
-6072.3729133606mm
2825.15907287598mm

```

## Goals
Expand Down
9 changes: 8 additions & 1 deletion src/MechanicalUnits.jl
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@ export ∙
# Import / exports for short and parseable type signatures
import Unitfu: Time, Length, Mass, Temperature, Current, Luminosity, Amount
import Unitfu: ᵀ , ᴸ , ᴹ , ᶿ, ᴶ , ᴺ
import Unitfu: lookup_units
export Time, Length, Mass, Temperature, Current, Luminosity, Amount, Level
export ᵀ , ᴸ , ᴹ , ᶿ , ᴶ , ᴺ
export Quantity, DimensionlessQuantity, NoUnits, NoDims
Expand All @@ -13,7 +14,7 @@ import Unitfu:
export FreeUnits, AffineUnits, Affine, AffineQuantity, Unitlike, Unit, Dimensions, Dimension, Units
export Level, Gain

# For importinng from Unitfu, or defining more units
# For importing from Unitfu, or defining more units
export @import_expand, @unit, @u_str

# Reexported functions from Unitfu
Expand All @@ -33,6 +34,10 @@ import Unitfu: Area, Acceleration, Force, Pressure, Density
import Unitfu: Velocity
import Unitfu:ForceFreeUnits, PressureFreeUnits, EnergyFreeUnits, AreaFreeUnits, DensityFreeUnits, VolumeFreeUnits
export Area, Acceleration, Force, Pressure, Density, Velocity

# Extend base. This could perhaps reside in Unitfu
import Base: tryparse_internal, parse

# Units are exported in 'import_export_units.jl'.

include("internal_functions.jl")
Expand All @@ -49,6 +54,7 @@ eval(exponents_superscripts(:ᴺ))
# Used for registering units with Unitfu macros during initialisation.
const localunits = Unitfu.basefactors

include("parse.jl")
function __init__()
# This is for evaluating Unitfu macros in the context of this package.
merge!(Unitfu.basefactors, localunits)
Expand All @@ -60,4 +66,5 @@ function __init__()
Sys.isapple() && push!(ENV, "UNITFUL_FANCY_EXPONENTS" => "true")
end


end # module
56 changes: 56 additions & 0 deletions src/parse.jl
Original file line number Diff line number Diff line change
@@ -0,0 +1,56 @@
parse(::Type{Quantity{T}}, s::AbstractString; kwargs...) where {T <: Real} =
convert(Quantity{T}, tryparse_internal(Quantity{T}, s, firstindex(s), lastindex(s), 10, true; kwargs...))

function tryparse_internal(::Type{Quantity{T}}, sbuff::Union{String,SubString{String}},
startpos::Int, endpos::Int, base::Integer, raise::Bool) where {T<:Real}
if isempty(sbuff)
raise && throw(ArgumentError("input string is empty"))
return nothing
end

orig_start = startpos
orig_end = endpos

# Ignore leading and trailing whitespace
while isspace(sbuff[startpos]) && startpos <= endpos
startpos = nextind(sbuff, startpos)
end
while isspace(sbuff[endpos]) && endpos >= startpos
endpos = prevind(sbuff, endpos)
end

# Find first character of unit specification
unitpos = startpos
while sbuff[unitpos] "+-0123456789.," && unitpos <= endpos
unitpos = nextind(sbuff, unitpos)
end

numlen = unitpos - startpos + 1
unitlen = endpos - unitpos + 1

if numlen > 0 && unitlen > 0
num = parse(T, sbuff[startpos:unitpos - 1])
suni = strip(sbuff[unitpos:endpos], ['[', ']', ' '])
if '/' suni
suni = replace(suni, r"[∙· *]" => '')
sunits = split(suni, '')
uni = lookup_units(MechanicalUnits, Symbol(sunits[1]))
for string_unit in sunits[2:lastindex(sunits)]
uni *= lookup_units(MechanicalUnits, Symbol(string_unit))
end
return num * uni
end
end

if raise
substr = SubString(sbuff, orig_start, orig_end) # show input string in the error to avoid confusion
if all(isspace, substr)
throw(ArgumentError("input string only contains whitespace"))
elseif '/' sbuff[unitpos:endpos]
throw(ArgumentError("input string contains '/' unit. Replace input with multiplied units: 'm/s' => 'm∙s⁻¹'"))
else
throw(ArgumentError("invalid quantity representation: $(repr(substr))"))
end
end
return nothing
end
11 changes: 11 additions & 0 deletions test/conversion_promotion.jl
Original file line number Diff line number Diff line change
Expand Up @@ -48,3 +48,14 @@ end
@test (1m, 1m^2/mm) == (1000, 1000000)mm
@test (1m, 1m^2/mm) == (1, 1000)m
end

@testset "Quantity parse" begin
@test parse(Quantity{Float64}, "2.0kN") == 2.0kN
@test parse(Quantity{Int64}, "2 kN") == 2kN
@test parse(Quantity{Int64}, "2 [m]") == 2m
@test parse(Quantity{Float64}, "2 [m]") == 2.0m
@test parse(Quantity{Float64}, "2 [N m]") == 2.0Nm
lin = "2 [s]\t11364.56982421875 [N]\t-44553.50244140625 [N]\t-26.586366176605225 [N]\t0.0[N mm]\t0.0[N mm]\t0.0[N mm]\t1561.00350618362 [mm]\t-6072.3729133606 [mm]\t2825.15907287598 [mm]"
data = parse.(Quantity{Float64}, split(lin, '\t'))
@test data == [ 2.0s, 11364.56982421875N, -44553.50244140625N, -26.586366176605225N, 0.0mmN, 0.0mmN, 0.0mmN, 1561.00350618362mm, -6072.3729133606mm, 2825.15907287598mm]
end

0 comments on commit d349c0f

Please sign in to comment.