So I'm trying to convert a binary to a string. This code:
t = [{<<71,0,69,0,84,0>>}]
String.from_char_list(t)
But I'm getting this when I try this conversion:
** (ArgumentError) argument error
(stdlib) :unicode.characters_to_binary([{<<70, 0, 73, 0, 78, 0>>}])
(elixir) lib/string.ex:1161: String.from_char_list/1
I'm assuming the <<70, 0, etc. is likely a list of graphemes (it's the return from an API call and the API is not quite documented) but do I need to specify the encoding somehow?
I know I'm likely missing something obvious (maybe that's not the right function to use?) but I can't seem to figure out what to do here.
EDIT:
For what it's worth, the binary above is the return value of an Erlang ODBC call. After a little more digging I found that the binary in question is actually a "Unicode binary encoded as UTF16 little endian" (see here: http://www.erlang.org/doc/apps/odbc/odbc.pdf pg. 9 re: SQL_WVARCHAR) Doesn't really change the issue but it does add some context.
The last point definitely does change the issue, and explains it. Elixir uses binaries as strings but assumes and demands that they are UTF8 encoded, not UTF16.
I made a function to convert binary to string
Executed on iex console
In reference to http://erlang.org/pipermail/erlang-questions/2010-December/054885.html
You can use
:unicode.characters_to_list(binary_string, {:utf16, :little})
to verify result and store tooIEX eval
Note : Value printed as
sys
for<<115, 0, 121, 0, 115, 0>>
You can use Comprehensions
There's a couple of things here:
1.) You have a list with a tuple containing one element, a binary. You can probably just extract the binary and have your string. Passing the current data structure to
to_string
is not going to work.2.) The binary you used in your example contains
0
, an unprintable character. In the shell, this will not be printed properly as a string, due to the fact that Elixir can't tell the difference between just a binary, and a binary representing a string, when the binary representing a string contains unprintable characters.3.) You can use pattern matching to convert a binary to a particular type. For instance:
Also, if you are getting binary data from a network connection, you probably want to use
:erlang.iolist_to_binary
, since the data will be an iolist, not a charlist. The difference is that iolists can contain binaries, nested lists, as well as just be a list of integers. Charlists are always just a flat list of integers. If you callto_string
, on an iolist, it will fail.Not sure if OP has since solved his problem, but in relation to his remark about his binary being
utf16-le
: for specifically that encoding, I found that the quickest (and to those more experienced with Elixir, probably-hacky) way was to useEnum.reduce
:Assumptions:
utf16-le
encodingthe codepoints are backwards-compatible with
utf8
i.e. they use only 1 byteSince I'm still learning Elixir, it took me a while to get to this solution. I looked into other libraries people made, even using something like
iconv
at a bash level.