2
votes

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.

1
Post input here, please.Aleksei Matiushkin
I updated the post.swidziniak
Could you please post an input bitstring? And the desired outcome as well.Aleksei Matiushkin
The bitstring input is "[{1,a},{2,3}]" (from conn.query_params) and the desired outcome is a following list of tuples: [{1,2}, {a,3}]swidziniak
this sounds like at least partially a question of HTML encoding... If you can control the input, why not pass the input in your URL as a JSON-encoded string?Everett

1 Answers

1
votes

: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}]}