Welcome to OGeek Q&A Community for programmer and developer-Open, Learning and Share
Welcome To Ask or Share your Answers For Others

Categories

0 votes
332 views
in Technique[技术] by (71.8m points)

cowboy - Elixir: accessing a list of tuples from query_param and iterating over it

I'm getting input via a query param like this: 127.0.0.1:8000/pair?A=[{A1,B1},{A2,B2},…,{An,Bn}]. I need to access that list of tuples and alter it, so that the result is a list of two tuples, the first one contains the first elements of each tuple in the original list, and the second tuple contains the second elements of each tuple, (like this [{A1,A2,…,An},{B1,B2,…,Bn}]) for example:

Input: [{a,5},{2,x},{r,r}]

Output: [{a,2,r},{5,x,r}]

The problem is that if I do:

conn = fetch_query_params(conn)
%{ "A" => input } = conn.query_params

the input variable is then bitstring, so I tried using input_parsed = :binary.bin_to_list input, but then if I'm trying to iterate over it like this:

output = Enum.map(input_parsed, fn {x, y} -> {x+y} end)

I'm getting the following errors:

(FunctionClauseError) no function clause matching in anonymous fn/1 in PwZadanie1.Router.do_match/4
        (pw_zadanie_1 0.1.0) lib/pw_zadanie1/router.ex:30: anonymous fn(91) in PwZadanie1.Router.do_match/4
        (elixir 1.11.3) lib/enum.ex:1411: Enum."-map/2-lists^map/1-0-"/2

91 is [ in ASCII so it's still not parsed.

I'm new to Elixir and would greatly appreciate any help with this. Thank you.


与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…
Welcome To Ask or Share your Answers For Others

1 Reply

0 votes
by (71.8m points)

:binary.bin_to_list is not going to help you here. If you have a binary like [{1,2},{3,4}] then you need to parse that to create the tuple list it represents. :binary.bin_to_list just gives you a list of bytes corresponding to the bytes in the string (as you see, 91 being the first one). :binary.bin_to_list doesn't try to understand the elixir or erlang semantics of the string.

The industry standard way to transfer this data (with semantic meaning intact) is JSON and when the JSON needs to go into a query parameter or (or other format sensitive field, like an HTTP header), it will generally be base64 encoded.

Ideally you would be able to change the front end to generate a base64 encoded json representation of the data and put that in the query parameter. Then on the backend just use a JSON parser to expand it back to a list of tuples. If the front end is not changeable, then you need to parse the query parameter yourself. If it's always an array of tuples of scalars then you can parse it yourself.

Technically you could put this string into Code.eval_string (docs) but please don't do this with untrusted input like query parameters. But for illustration purposes only you can see that for this example input Code.eval_string would return the list you're looking for.

A safer option is Code.string_to_quoted which will compile the string you give it but does not execute it.

iex(1)> Code.string_to_quoted("[{"a",5}, {"b", 4}]")
{:ok, [{"a", 5}, {"b", 4}]}

与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…
OGeek|极客中国-欢迎来到极客的世界,一个免费开放的程序员编程交流平台!开放,进步,分享!让技术改变生活,让极客改变未来! Welcome to OGeek Q&A Community for programmer and developer-Open, Learning and Share
Click Here to Ask a Question

...