#julia
Вопрос:
я получаю список, который был сохранен в виде строки, и пытаюсь разобрать его для использования. Я могу использовать Meta.parse, чтобы превратить строку в выражение :
li = db.list
print(typeof(d[1]),d[1])
>> String
["apple", "banana", "coconut"]
parsed_li = Meta.parse(d[1])
print(typeof(parsed_li), parsed_li)
>> Expr
["apple", "banana", "coconut"]
но не похоже, что я могу использовать его как обычный список; например, с помощью обычного списка я мог бы получить доступ к элементу по его индексу, но я не могу получить доступ к индексу объекта Expr :
normal_li = ["apple", "banana", "coconut"]
print(normal_li[1])
>> apple
print(parsed_li[1])
>>
MethodError: no method matching getindex(::Expr, ::Int64)
Stacktrace:
[1] top-level scope at In[214]:8
я возился, не уверен, чего мне здесь не хватает!
Ответ №1:
Полагаться на Meta.parse()
синтаксический анализ ваших входных данных неэффективно и небезопасно (вредоносный код всегда может быть вставлен во входные данные, и вы можете что-то делать eval
с ним и т. Д.). Вместо этого вы предпочитаете использовать инструменты, предназначенные именно для этого. В вашем случае просто обратите внимание, что эти данные можно рассматривать как допустимый формат JSON и их можно прочитать следующим образом:
julia> str = """["apple", "banana", "coconut"]"""
"["apple", "banana", "coconut"]"
julia> using JSON3
julia> JSON3.read(str)
3-element JSON3.Array{String, Base.CodeUnits{UInt8, String}, Vector{UInt64}}:
"apple"
"banana"
"coconut"
julia> collect(JSON3.read(str))
3-element Vector{String}:
"apple"
"banana"
"coconut"
Если вы доверяете входным данным (обычно вы никогда не должны), вы можете сделать это небезопасным способом:
julia> eval(Meta.parse(str))
3-element Vector{String}:
"apple"
"banana"
"coconut"
Если вы хотите извлечь информацию без eval
, это можно сделать с помощью args
поля Expr
объекта — однако способ его обработки будет каждый раз сильно зависеть от структуры данных:
julia> Meta.parse(str).args
3-element Vector{Any}:
"apple"
"banana"
"coconut"
Комментарии:
1. Хороший момент о вредоносном вводе. Поверхностной проверки
Expr
заголовка недостаточно даже для гарантииeval
безопасности. Например,parsed_li.head
естьvect
, и можно подумать: «ну, это не гигантский блок кода или метод, это просто массив». Однако это тоже массив :["apple", delete_all_your_files_and_steal_your_cat(), "coconut"]
.
Ответ №2:
Это всегда внизу на странице документов: evaled_li = eval(parsed_li)
будет вектором строки.
Ответ №3:
Expr
это не структура данных, подобная списку.
Цитируется по документу
Expr
Тип, представляющий составные выражения в проанализированном коде Julia (ASTs). Каждое выражение состоит из
head
Symbol
указания, к какому виду выражения оно относится (например, вызов, цикл for, условный оператор и т.д.), И подвыражений (например, аргументы вызова). Подвыражения хранятся в вызываемомVector{Any}
полеargs
.
Вы все равно можете получить доступ к этим элементам через args
поле, хотя, если хотите.
Комментарии:
1. да, мой вопрос был в том, можно ли его преобразовать в массив
2. Хм, я думал, было ясно, что
args
поле — это то, что вы хотите в данном конкретном случае? В противном случае я не видел ничего осмысленного в преобразовании двоичной древовидной структуры в список здесь.3.
parsed_li.args
на самом деле является вектором Any. Выражение еще не было вычислено, поэтому оноargs
будет содержать векторы литералов (String, Int, Float64), Symbol или другого выражения. Поскольку ваш массив изначально содержал только строки, этого было бы достаточно.