Skip to content

Commit f71228d

Browse files
authored
fix unicode indexing in parse(Complex, string) (#51758)
This fixes a string-indexing bug introduced in #24713 (Julia 0.7). Sometimes, this would cause `parse(Complex{T}, string)` to throw a `StringIndexError` rather than an `ArgumentError`, e.g. for `parse(ComplexF64, "3 β+ 4im")` or `parse(ComplexF64, "3 + 4αm")`. (As far as I can tell, it can never cause parsing to fail for valid strings.) The source of the error is that if `i` is the index of an ASCII character in a string `s`, then `s[i+1]` is valid (even if the next character is non-ASCII) but `s[i-1]` is invalid if the previous character is non-ASCII.
1 parent 6d1c0a0 commit f71228d

File tree

2 files changed

+7
-5
lines changed

2 files changed

+7
-5
lines changed

base/parse.jl

+5-5
Original file line numberDiff line numberDiff line change
@@ -321,14 +321,14 @@ function tryparse_internal(::Type{Complex{T}}, s::Union{String,SubString{String}
321321
if i₊ == i # leading ± sign
322322
i₊ = something(findnext(in(('+','-')), s, i₊+1), 0)
323323
end
324-
if i₊ != 0 && s[i₊-1] in ('e','E') # exponent sign
324+
if i₊ != 0 && s[prevind(s, i₊)] in ('e','E') # exponent sign
325325
i₊ = something(findnext(in(('+','-')), s, i₊+1), 0)
326326
end
327327

328328
# find trailing im/i/j
329329
iᵢ = something(findprev(in(('m','i','j')), s, e), 0)
330330
if iᵢ > 0 && s[iᵢ] == 'm' # im
331-
iᵢ -= 1
331+
iᵢ = prevind(s, iᵢ)
332332
if s[iᵢ] != 'i'
333333
raise && throw(ArgumentError("expected trailing \"im\", found only \"m\""))
334334
return nothing
@@ -337,7 +337,7 @@ function tryparse_internal(::Type{Complex{T}}, s::Union{String,SubString{String}
337337

338338
if i₊ == 0 # purely real or imaginary value
339339
if iᵢ > i && !(iᵢ == i+1 && s[i] in ('+','-')) # purely imaginary (not "±inf")
340-
x = tryparse_internal(T, s, i, iᵢ-1, raise)
340+
x = tryparse_internal(T, s, i, prevind(s, iᵢ), raise)
341341
x === nothing && return nothing
342342
return Complex{T}(zero(x),x)
343343
else # purely real
@@ -353,11 +353,11 @@ function tryparse_internal(::Type{Complex{T}}, s::Union{String,SubString{String}
353353
end
354354

355355
# parse real part
356-
re = tryparse_internal(T, s, i, i₊-1, raise)
356+
re = tryparse_internal(T, s, i, prevind(s, i₊), raise)
357357
re === nothing && return nothing
358358

359359
# parse imaginary part
360-
im = tryparse_internal(T, s, i₊+1, iᵢ-1, raise)
360+
im = tryparse_internal(T, s, i₊+1, prevind(s, iᵢ), raise)
361361
im === nothing && return nothing
362362

363363
return Complex{T}(re, s[i₊]=='-' ? -im : im)

test/parse.jl

+2
Original file line numberDiff line numberDiff line change
@@ -296,6 +296,8 @@ end
296296
@test_throws ArgumentError parse(Complex{T}, bad)
297297
end
298298
@test_throws ArgumentError parse(Complex{Int}, "3 + 4.2im")
299+
@test_throws ArgumentError parse(ComplexF64, "3 β+ 4im")
300+
@test_throws ArgumentError parse(ComplexF64, "3 + 4αm")
299301
end
300302

301303
@testset "parse and tryparse type inference" begin

0 commit comments

Comments
 (0)