从字符串中解析 Elixir 术语
Parse Elixir Terms From A String
Erlang 具有从字符串中解析 Erlang 术语的功能。这具有避免动态代码执行(即不信任用户输入)的优点,但允许用户输入任何有效的文字值。
参见:http://www.erlang.org/faq/how_do_i.html#idp32770608
Elixir 是否允许类似的东西?我可以轻松地接受一个字符串并尝试解析它吗?
理想情况下它看起来像:
str = "{:foo, %{bar: true}, nil}"
Elixir.parse_term(str) # => {:foo, %{bar: true}, nil}
使用 Elixir 模式匹配这很容易:
defmodule ParseTerm do
def parse(str) when is_binary(str)do
case str |> Code.string_to_quoted do
{:ok, terms} -> {:ok, _parse(terms)}
{:error, _} -> {:invalid_terms}
end
end
# atomic terms
defp _parse(term) when is_atom(term), do: term
defp _parse(term) when is_integer(term), do: term
defp _parse(term) when is_float(term), do: term
defp _parse(term) when is_binary(term), do: term
defp _parse([]), do: []
defp _parse([h|t]), do: [_parse(h) | _parse(t)]
defp _parse({a, b}), do: {_parse(a), _parse(b)}
defp _parse({:"{}", _place, terms}) do
terms
|> Enum.map(&_parse/1)
|> List.to_tuple
end
defp _parse({:"%{}", _place, terms}) do
for {k, v} <- terms, into: %{}, do: {_parse(k), _parse(v)}
end
defp _parse({_term_type, _place, terms}), do: terms # to ignore functions and operators
end
这样使用:
iex(1)> ParseTerm.parse "%{1=>:a, :q=>:z, :w => [1,2, 1.618, {1,2, %{a: \"1.2\" } }] }"
{:ok, %{1 => :a, :q => :z, :w => [1, 2, 1.618, {1, 2, %{a: "1.2"}}]}}
Erlang 具有从字符串中解析 Erlang 术语的功能。这具有避免动态代码执行(即不信任用户输入)的优点,但允许用户输入任何有效的文字值。
参见:http://www.erlang.org/faq/how_do_i.html#idp32770608
Elixir 是否允许类似的东西?我可以轻松地接受一个字符串并尝试解析它吗?
理想情况下它看起来像:
str = "{:foo, %{bar: true}, nil}"
Elixir.parse_term(str) # => {:foo, %{bar: true}, nil}
使用 Elixir 模式匹配这很容易:
defmodule ParseTerm do
def parse(str) when is_binary(str)do
case str |> Code.string_to_quoted do
{:ok, terms} -> {:ok, _parse(terms)}
{:error, _} -> {:invalid_terms}
end
end
# atomic terms
defp _parse(term) when is_atom(term), do: term
defp _parse(term) when is_integer(term), do: term
defp _parse(term) when is_float(term), do: term
defp _parse(term) when is_binary(term), do: term
defp _parse([]), do: []
defp _parse([h|t]), do: [_parse(h) | _parse(t)]
defp _parse({a, b}), do: {_parse(a), _parse(b)}
defp _parse({:"{}", _place, terms}) do
terms
|> Enum.map(&_parse/1)
|> List.to_tuple
end
defp _parse({:"%{}", _place, terms}) do
for {k, v} <- terms, into: %{}, do: {_parse(k), _parse(v)}
end
defp _parse({_term_type, _place, terms}), do: terms # to ignore functions and operators
end
这样使用:
iex(1)> ParseTerm.parse "%{1=>:a, :q=>:z, :w => [1,2, 1.618, {1,2, %{a: \"1.2\" } }] }"
{:ok, %{1 => :a, :q => :z, :w => [1, 2, 1.618, {1, 2, %{a: "1.2"}}]}}