UnitfulParsableString.jl
expand Unitful.jl to add the multiple dispatch of Base.string
which convert Quantity
(or some type) to parsable String
.
julia> using Unitful
julia> string(1.0u"m*s")
"1.0 m s" # <- julia cannot parse
julia> string(1.0u"m*s") |> Unitful.uparse
ERROR: Base.Meta.ParseError("extra token \"m\" after end of expression")
julia> using UnitfulParsableString
julia> string(1.0u"m*s")
"1.0(m*s)" # <- julia can parse
julia> string(1.0u"m*s") |> Unitful.uparse
1.0 m s
string(unit::Units)
Values of Unitful.Units
subtypes are converted to string
that julia can parse as following rules.
Multi-units are expressed as basicaly separeted by "*"
, but sometimes "/"
is used exceptionally for simplicity, see below for details.
Exponents are expressed as "^x"
or "^-x"
(x > 0) in principle, except for units with a rational exponent y, which are expressed by wrapping them in parentheses as "^(y)"
.
When all exponential of the units is positive, all separates are "*"
.
julia> string(u"m*s^2")
"m*s^2"
When all exponential of the units is negative, all separates are "*"
and the negative exponential is expressed as "^-|w|"
.
julia> string(u"(m*s)^-1") # all exponents are negative
"m^-1*s^-1" # -> separater is "*"
When both positive and negative exponentials coexist, if there are rational exponentials, all separates are "*"
and the negative exponential is expressed as "^-|w|"
.
julia> string(u"m^(1/2)*s^-2") # positive and negative exponent coexist
"m^(1/2)*s^-2" # if rational exponent exist -> separater is "*"
When both positive and negative exponentials coexist, if not there are rational exponentials, the separates of the units with negative exponential are "/"
and the negative exponential is expressed as "^|w|"
.
julia> string(u"m*s^-2") # positive and negative exponent coexist
"m/s^2" # if rational exponent never exist -> "/" can be use for separater
When the exponentials are rational, if the velue n//m is strictly same as n/m, it is expressed as "^(n/m)".
julia> string(u"m^(1//2)") # 1//2 == 1/2
"m^(1/2)"
If not the velue n//m is strictly same as n/m, it is expressed as "^(n//m)".
julia> string(u"m^(1//3)") # 1//3 != 1/3
"m^(1//3)"
string(x::Quantity)
Values of Unitful.Quantity
subtypes to string
that julia can parse as following rules.
The Unitful.Quantity
x
have value and units (they can be get x.val
and unit(x)
).
Thus, the work of this function is simply shown as follows:
string( ["(",] string(value), [")",] ["*",] ["(",] string(units) [,")"] )
The presence or absence of each bracket is determined by the return values of the has_value_bracket(x)
and has_unit_bracket(x)
functions.
And the sepaprator "*"
is inserted, if has_value_bracket(x) && has_unit_bracket(x) == true
.
The has_value_bracket(x)
returns false if string(x)
contains only digits, and true if it contains non-digits.
However, if typeof(x)
is a specific type, the process is lightened by multiple dispatching.
The has_unit_bracket(x)
returns false if the unit(x)
consists of single type unit, and true if it consists of multi type units.
Note: see string(x::Unitlike)
about the string expression of unit.
Note: if unit(x)
== NoUnits, this method output only string(x.val)
.
At the case of Int
the bracket is absence and, at the case of the unit consists of only s
the bracket is absence.
has_value_bracket(x) = false
&& has_unit_bracket(x) == false
julia> string(u"1s^2") # u"1s^2" -> 1 s²
"1s^2"
At the case of Float64
the bracket is absence and, at the case of the unit consists of kg
and m
the bracket is presence.
has_value_bracket(x) = false
&& has_unit_bracket(x) == true
julia> string(u"1.0m*kg") # u"1.0m*kg" -> 1.0 kg m
"1.0(kg*m)"
At the case of Rational
the bracket is presence and, at the case of the unit consists of m
the bracket is absence.
has_value_bracket(x) = true
&& has_unit_bracket(x) == false
julia> string((1//2)u"m") # (1//2)u"m" -> 1//2 m
"(1//2)m"
At the case of Rational
the bracket is presence and, at the case of the unit consists of m
and s
the bracket is presence.
has_value_bracket(x) = true
&& has_unit_bracket(x) == true
julia> string((1+2im)u"m/s") # (1+2im)u"m/s" -> (1 + 2im) m s⁻¹
"(1 + 2im)*(m/s)"
julia> using UnitfulParsableString
julia> x = u"1.0m^2/K^(1//3)"
1.0 m² K⁻¹ᐟ³
julia> x |> string |> uparse == x
true
julia> x = 2u"m"//3u"s"
2//3 m s⁻¹
julia> x |> string |> uparse == x
true
See more test/runtest.jl.
UnitfulParsableString.jl
not change the display
, show
and print
functions about Unitful.jl
.
julia> using Unitful
julia> 1.0u"m"
1.0 m
julia> 1.0u"m*s"
1.0 m s
julia> using UnitfulParsableString
julia> 1.0u"m"
1.0 m
julia> 1.0u"m*s"
1.0 m s
This package not support Logscaled
units i.e., Gain
or Lebel
yet.
Array
of Quantity
is now supported, but implementation is too rough. Please use at your own risk.
The expressions of unit
is controlled whether to use u_str
(u"~"
) by this function.
julia> using Unitful, UnitfulParsableString
julia> UnitfulParsableString.ustrexpression() # default
false
julia> string(1.0u"m^2/s^3")
"1.0(m^2/s^3)"
julia> UnitfulParsableString.ustrexpression(true)
true
julia> string(1.0u"m^2/s^3")
"1.0u\"m^2/s^3\""
This u_str
expression is useful for the evaluation in the Main
module.
julia> UnitfulParsableString.ustrexpression(true);
julia> string(1.0u"m/s/kg^2") |> Meta.parse |> eval # no need to use `Unitful.eval`
1.0 m kg⁻² s⁻¹
The expressions of unit
is controlled whether to use "/"
or "*"
in the case of division operation by this function.
julia> using Unitful, UnitfulParsableString
julia> UnitfulParsableString.slashnotation() # default
true
julia> string(1.0u"m/s/kg^2")
"1.0(m/kg^2/s)"
julia> UnitfulParsableString.slashnotation(false)
false
julia> string(1.0u"m/s/kg^2")
"1.0(m*kg^-2*s^-1)"
- Unitful.jl - Implements dimensional numerical quantities for Julia