I can parse(Int, „123“) but I cannot find a simple way to parse(Vector{Int}, „[1, 2, 3]”). Is there a “canned” solution?
Broadcast the function.
x = ["1", "2", "3"]
y = parse.(Int64,x)
If it is arbitrary julia code you can Meta.parse
and eval it it but perhaps using something like JSON would be more suitable here?
If you just need to parse this exact format, splitting on the comma and broadcasting the parse
would likely be the most efficient.
Not necessarily sure if it is always faster to broadcast and do multiple calls to the parser instead of calling the parser a single time to instead parse a slightly larger string. Might be better sometimes to make single call.
The julia source code parser and the parser that parses types like Int
s are two completely different things.
julia> f(x) = parse(Int, x)
f (generic function with 1 method)
julia> @btime f("2")
46.842 ns (0 allocations: 0 bytes)
2
julia> g(x) = Meta.parse(x)
f (generic function with 1 method)
julia> @btime g("2")
19.187 μs (7 allocations: 208 bytes)
2
You should only use Meta.parse
if you are parsing actual julia source code.
As a simple solution in the past I’ve used:
@assert str[1] == '[' && str[end] == ']'
CSV.read(IOBuffer(str[2:prevind(str, end)]), header=false, transpose=true)
Thank you - I was looking as CSC but didn’t see this trick.
For curiosity, if I am given a strIng as Inshowed then how do Inconvert it into an array of strings?
Sorry for misunderstanding earlier. Here’s something you can do if you really have to work with the string "[1, 2, 3]"
x = "[1, 2, 3]"
rr = r"([0-9])" # you can alter this to work with numbers with decimal places
matches = [parse(Int64,t.match) for t in eachmatch(rr, x)]
> 3-element Array{Int64,1}:
1
2
3
Very interesting, thank you. I’ll need to spend some time understanding this
Another workaround is to make it a full expression
vec = "[1, 2, 3]"
y = "y = "
t = y * vec
out = eval(parse(t))
Definitely don’t do that. Using eval
— and especially eval(parse(…))
— is a major red flag. It doesn’t work the way you expect within functions and it is prone to security issues and surprising bugs.
Hi! I’m a bit of a metaprogramming noob but I’d like to understand a bit better why parsing a string that looks like the definition of a vector could be a bad idea. If you can point me to some relevant documentation I’d be very happy
See this thread: How to warn new users away from metaprogramming, e.g. my comment on avoiding misuse of metaprogramming: How to warn new users away from metaprogramming - #22 by stevengj
Thanks a lot! Your comment and many other valid points in the thread were quite useful.
The bigger problem than Meta.parse
is eval
:
Julia’s eval
only works at global scope. If you do something like eval(parse("y = [1,2,3]"))
, it’ll create a global y
that’s separate from any local y
s you might have inside your function. At best, it’ll be very slow and fragile.
Especially if you’re parsing user input.
julia> eval(Meta.parse("[1,2,3,run(`echo 'rm -rf /'`)]"));
rm -rf /
Oops.
that’s a pretty good example! thanks
awesome solution. works perfectly for me. thanks
a slightly different version but similar to other proposals
vecfromstr(str)=parse.(Int,split(filter(x->isdigit(x)||x==',', str),','))
this expression gives me the following error
julia> CSV.read(IOBuffer(str[2:prevind(str, end)]), header=false, transpose=true)
ERROR: ArgumentError: provide a valid sink argument, like `using DataFrames; CSV.read(source, DataFrame)`