だから私はバイナリを文字列に変換しようとしています。このコード:
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
<< 70、0などはおそらく書記素のリストであると思います(これはAPI呼び出しからの戻りであり、APIは完全に文書化されていません)が、何らかの方法でエンコーディングを指定する必要がありますか?
明らかな何かが欠けている可能性があることは知っていますが(おそらくそれは使用するのに適切な関数ではありませんか?)、ここで何をすべきか理解できないようです。
編集:
上記のバイナリは、Erlang ODBC呼び出しの戻り値です。もう少し掘り下げてみると、問題のバイナリは実際には「UTF16リトルエンディアンとしてエンコードされたUnicodeバイナリ」であることがわかりました。 "(ここを参照: http://www.erlang.org/doc/apps/odbc/odbc.pdf pg。9 re:SQL_WVARCHAR)実際には問題は変更されませんが、いくつか追加されます環境。
ここにはいくつかのことがあります。
1.)1つの要素(バイナリ)を含むタプルのリストがあります。おそらく、バイナリを抽出して文字列を取得できます。現在のデータ構造をto_string
に渡しても機能しません。
2.)例で使用したバイナリには、印刷できない文字である0
が含まれています。シェルでは、文字列を表すバイナリに印刷できない文字が含まれている場合、バイナリのみと文字列を表すバイナリの違いを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"
また、ネットワーク接続からバイナリデータを取得する場合は、データがcharlistではなくiolistになるため、おそらく:erlang.iolist_to_binary
を使用することをお勧めします。違いは、iolistにはバイナリ、ネストされたリスト、および単なる整数のリストを含めることができることです。文字リストは常に整数の単なるフラットリストです。 iolistでto_string
を呼び出すと、失敗します。
バイナリを文字列に変換する関数を作成しました
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"
OPがその後問題を解決したかどうかはわかりませんが、彼のバイナリがutf16-le
であるという彼の発言に関連して、特にそのエンコーディングについては、最も速い(そしてElixirの経験が豊富な人にとってはおそらくハッキーな)方法であることがわかりましたEnum.reduce
を使用することでした:
# 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>>]
<<68, 0, 101, 0, 118, 0, 97, 0, 115, 0, 116, 0, 97, 0, 116, 0, 111, 0, 114, 0>>
|> String.codepoints()
|> Enum.reduce("", fn(codepoint, result) ->
<< parsed :: 8>> = codepoint
if parsed == 0, do: result, else: result <> <<parsed>>
end)
# "Devastator"
|> IO.puts()
仮定:
utf16-le
エンコード
コードポイントはutf8
と下位互換性があります。つまり、1バイトのみを使用します
私はまだElixirを学んでいるので、この解決策にたどり着くまでに少し時間がかかりました。 iconv
のようなものをbashレベルで使用していても、人々が作成した他のライブラリを調べました。
最後のポイントは間違いなくします問題を変更し、それを説明します。 Elixirはバイナリを文字列として使用しますが、UTF16ではなくUTF8でエンコードされていることを前提として要求します。
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'
注:<<115, 0, 121, 0, 115, 0>>
に対してsys
として出力される値
内包表記を使用できます
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