-
-
Notifications
You must be signed in to change notification settings - Fork 5.6k
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
add parse(Complex{T}, string) #22250
Comments
IMO:
|
I agree with @ararslan on all points, although I don't feel strongly about whether If arbitrary whitespace doesn't end up allowed between the real and imaginary parts, then spaces should be required around the |
I'm inclined to support |
I'm reluctant to support |
Here's a possible implementation that supports whitespace, purely real values, and i/j/im suffixes. It seems to be about 1000x faster than import Base: tryparse, parse
function tryparse(::Type{Complex{T}}, s::String) where {T<:Real}
# skip initial whitespace
i = start(s)
e = endof(s)
while i ≤ e && isspace(s[i])
i = nextind(s, i)
end
i > e && return Nullable{Complex{T}}()
# find index of ± separating real/imaginary parts (if any)
i₊ = search(s, ('+','-'), i)
if i₊ == i # leading ± sign
i₊ = search(s, ('+','-'), i₊+1)
end
if i₊ != 0 && s[i₊-1] in ('e','E','f') # exponent sign
i₊ = search(s, ('+','-'), i₊+1)
end
if i₊ == 0 # purely real value
return Nullable{Complex{T}}(tryparse(T, s))
end
# find trailing im/i/j
iᵢ = rsearch(s, ('m','i','j'), e)
iᵢ < i₊ && return Nullable{Complex{T}}()
if s[iᵢ] == 'm' # im
iᵢ -= 1
s[iᵢ] == 'i' || return Nullable{Complex{T}}()
end
isdigit(s[iᵢ-1]) || return Nullable{Complex{T}}()
# parse real part
re = tryparse(T, SubString(s, i, i₊-1))
isnull(re) && return Nullable{Complex{T}}()
# parse imaginary part
im = tryparse(T, SubString(s, i₊+1, iᵢ-1))
isnull(im) && return Nullable{Complex{T}}()
return Nullable{Complex{T}}(Complex{T}(get(re), s[i₊]=='-' ? -get(im) : get(im)))
end
# the ±1 indexing above for ascii chars is specific to String, so convert:
tryparse(T::Type{<:Complex}, s::AbstractString) = tryparse(T, String(s))
# can be merged with parse(::Type{<:AbstractFloat}, s::AbstractString):
function parse(::Type{T}, s::AbstractString) where T<:Complex
result = tryparse(T, s)
if isnull(result)
throw(ArgumentError("cannot parse $(repr(s)) as $T"))
end
return unsafe_get(result)
end |
(Could be a bit faster if we implement specialized |
As @ChrisRackauckas points out on discourse, this shouldn't really be done in a package because
Base.parse
and all of the argument types are "owned" by Base.Would also be nice not to have to use horribly inefficient techniques involving
eval
; see also #21935.Should be straightforward to implement. The main question in my mind is how permissive it should be:
"3+4im"
and3 + 4im
both allowed?im
, or accept the common variantsim
,i
,j
, andI
?3+4im
, or also allow3+4*im
?(real,imag)
? (Probably not, since we don't support Fortran-style real literals1.0D+00
either.)The text was updated successfully, but these errors were encountered: