所以我试图将二进制文件转换为字符串。这段代码:
t = [{<<71,0,69,0,84,0>>}]
String.from_char_list(t)
但是当我尝试这种转换时,我得到了这个:
** (ArgumentError) argument error
(stdlib) :unicode.characters_to_binary([{<<70, 0, 73, 0, 78, 0>>}])
(elixir) lib/string.ex:1161: String.from_char_list/1
我假设&lt;&lt;&lt;&lt;&lt;&lt;&lt;&lt;&lt;&lt;&lt;&lt; 70,0等可能是一个字素列表(它是API调用的返回,API没有完全记录)但我是否需要以某种方式指定编码?
我知道我可能会遗漏一些明显的东西(也许这不是正确的功能?)但我似乎无法弄明白该做什么。
编辑:
对于它的价值,上面的二进制文件是Erlang ODBC调用的返回值。经过一番挖掘后,我发现所讨论的二进制文件实际上是一个编码为UTF16小端的&#34; Unicode二进制文件&#34; (请参阅此处:http://www.erlang.org/doc/apps/odbc/odbc.pdf第9页re:SQL_WVARCHAR)确实没有改变问题,但它确实添加了一些上下文。
答案 0 :(得分:19)
这里有几件事情:
1。)你有一个包含一个元素的元组列表,一个二进制文件。您可以只提取二进制文件并使用您的字符串。将当前数据结构传递给String.from_char_list
是行不通的。
2。)您在示例中使用的二进制文件包含0
,一个不可打印的字符。在shell中,由于Elixir无法区分二进制文件和表示字符串的二进制文件,而表示字符串的二进制文件包含不可打印的字符,因此不会将其正确打印为字符串。
3.。)您可以使用模式匹配将二进制转换为特定类型。例如:
iex> raw = <<71,32,69,32,84,32>>
...> Enum.join(for <<c::utf8 <- raw>>, do: <<c::utf8>>)
"G E T "
...> <<c::utf8, _::binary>> = raw
"G"
此外,如果您从网络连接获取二进制数据,您可能希望使用:erlang.iolist_to_binary
,因为数据将是一个iolist,而不是charlist。不同之处在于,iolists可以包含二进制文件,嵌套列表,以及只是一个整数列表。查尔斯列表总是只是一个整数列表。如果你在iolist上拨打String.from_char_list
,它就会失败。
答案 1 :(得分:3)
不确定OP是否已经解决了他的问题,但是关于他关于他的二进制文件utf16-le
的评论:对于特别是编码,我发现最快(对于那些更有经验的Elixir,可能 - hacky)方式是使用Enum.reduce
:
raw = <<68, 0, 101, 0, 118, 0, 97, 0, 115, 0, 116, 0, 97, 0, 116, 0, 111, 0, 114, 0>>
# coercing it into utf8 gives us ["D", <<0>>, "e", <<0>>, "v", <<0>>, "a", <<0>>, "s", <<0>>, "t", <<0>>, "a", <<0>>, "t", <<0>>, "o", <<0>>, "r", <<0>>]
codepoints = String.codepoints(raw)
value = Enum.reduce(codepoints, "", fn(codepoint, result) ->
<< parsed :: 8>> = codepoint
if parsed == 0, do: result, else: result <> <<parsed>>
end)
# "Devastator"
IO.puts(value)
假设:
utf16-le
编码
代码点向后兼容utf8
,即它们只使用1个字节
由于我还在学习Elixir,我花了一些时间来解决这个问题。我查看了人们制作的其他图书馆,甚至在bash级别使用iconv
之类的东西。
答案 2 :(得分:3)
我创建了一个将二进制转换为字符串
的函数def raw_binary_to_string(raw) do
codepoints = String.codepoints(raw)
val = Enum.reduce(codepoints,
fn(w, result) ->
cond do
String.valid?(w) ->
result <> w
true ->
<< parsed :: 8>> = w
result <> << parsed :: utf8 >>
end
end)
end
在iex控制台上执行
iex(6)>raw=<<65, 241, 111, 32, 100, 101, 32, 70, 97, 99, 116, 117, 114, 97, 99, 105, 111, 110, 32, 65, 99, 116, 117, 97, 108>>
iex(6)>raw_binary_to_string(raw)
iex(6)>"Año de Facturacion Actual"
答案 3 :(得分:1)
最后一点肯定确实更改了问题并解释了它。 Elixir使用二进制文件作为字符串,但假定并要求它们是UTF8编码,而不是UTF16。
答案 4 :(得分:1)
关于http://erlang.org/pipermail/erlang-questions/2010-December/054885.html
您也可以使用:unicode.characters_to_list(binary_string, {:utf16, :little})
来验证结果并存储
IEX评估
iex(1)> y
<<115, 0, 121, 0, 115, 0>>
iex(2)> :unicode.characters_to_list(y, {:utf16, :little})
'sys'
注意:将值sys
打印为<<115, 0, 121, 0, 115, 0>>
答案 5 :(得分:1)
您可以使用理解力
defmodule TestModule do
def convert(binary) do
for c <- binary, into: "", do: <<c>>
end
end
TestModule.convert([71,32,69,32,84,32]) |> IO.puts