转换UTF-8 ISO-8859字节-String.to_charlist

时间:2018-08-01 12:03:49

标签: utf-8 elixir

我遇到了一个奇怪的问题。我有一个程序可以从外部源接收以字节为单位的数据,作为回报,我可以执行一些业务逻辑并发送回复。我们在String.to_charlist中遇到了一个奇怪的问题。

在iex中尝试一下:

String.to_charlist <<169, 99, 111, 114, 94, 51, 94, 51, 94, 66, 52, 57, 49, 49, 49, 32, 32, 49, 48, 51, 53, 94, 67, 79, 77, 80, 76, 69, 84, 69, 68, 94, 49, 49, 52, 50, 52, 53, 94, 75>>

这将引发以下错误:

** (UnicodeConversionError) invalid encoding starting at <<169, 99, 111, 114, 94, 51, 94, 51, 94, 66, 52, 57, 49, 49, 49, 32, 32, 49, 48, 51, 53, 94, 67, 79, 77, 80, 76, 69, 84, 69, 68, 94, 49, 49, 52, 50, 52, 53, 94, 75>>
    (elixir) lib/string.ex:2035: String.to_charlist/1

现在,如果您剥离第一个字节,然后依次尝试:

String.to_charlist <<99, 111, 114, 94, 51, 94, 51, 94, 66, 52, 57, 49, 49, 49, 32, 32, 49, 48, 51, 53, 94, 67, 79, 77, 80, 76, 69, 84, 69, 68, 94, 49, 49, 52, 50, 52, 53, 94, 75>>

您得到:

  

'cor ^ 3 ^ 3 ^ B49111 1035 ^ COMPLETED ^ 114245 ^ K'

我应该以其他方式将这些字节转换为字符串吗?我了解某些字符(例如169)可能无法显示,但是推荐的处理方式是什么?

感谢您的帮助。

我确实找到了:

<<169 :: utf8, 0>> 

返回添加了194的<< 194、169、0 >>。因此,如果将其粘贴到iex中,则输出似乎正确。

<<194, 169, 99, 111, 114, 94, 51, 94, 51, 94, 66, 52, 57, 49, 49, 49, 32, 32, 49, 48, 51, 53, 94, 67, 79, 77, 80, 76, 69, 84, 69, 68, 94, 49, 49, 52, 50, 52, 53, 94, 75>> 

我是否需要编写一个循环遍历字节并调用<>然后减少返回的字节数的函数(0 concat除外)?

1 个答案:

答案 0 :(得分:1)

String.to_charlist/1首先是多余的:

String.to_charlist <<99, 111, 114, 94, 51, 94, 51, 94>>

之所以起作用,是因为utf8latin1在间隔1–127中共享相同的代码点。以下内容足以获取完美有效的二进制文件:

<<99, 111, 114, 94, 51, 94, 51, 94>>
#⇒ "cor^3^3^"

不幸的是,您收到的不是utf8编码格式,Elixir没有内置工具可以在编码之间转换二进制文件。您不能只删除有意义的符号。

我建议使用codepagex包进行该转换:

Codepagex.from_string(<<99, 111, 114, 94, 51, 94, 51, 94>>, :iso_8859_1)
#⇒ "cor^3^3^"

另一种方法是使用erlang的unicode.characters_to_binary/2

:unicode.characters_to_binary(
  <<169, 99, 111, 114, 94, 51, 94, 51, 94>>, :latin1, :utf8
)
#⇒ "©cor^3^3^"

使用Kernel.SpecialForms.for/1理解的另一种解决方案:

to_string(for <<c :: 8 <- <<169, 99, 111, 114, 94, 51, 94, 51, 94>> >>, do: c)
#⇒ "©cor^3^3^"