web-dev-qa-db-ja.com

エリクサーバイナリを文字列に変換する方法

だから私はバイナリを文字列に変換しようとしています。このコード:

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)実際には問題は変更されませんが、いくつか追加されます環境。

13

ここにはいくつかのことがあります。

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を呼び出すと、失敗します。

22
bitwalker

バイナリを文字列に変換する関数を作成しました

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"
5
Andres Garcia

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レベルで使用していても、人々が作成した他のライブラリを調べました。

4
user701847

最後のポイントは間違いなくします問題を変更し、それを説明します。 Elixirはバイナリを文字列として使用しますが、UTF16ではなくUTF8でエンコードされていることを前提として要求します。

2
rvirding

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として出力される値

1
Pikender Sharma

内包表記を使用できます

    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
1
Thomas Thornier