【问题标题】:Is there a non-heuristic way of finding the encoding of a string (ie. list)?是否有一种非启发式的方式来查找字符串(即列表)的编码?
【发布时间】:2015-08-17 00:43:13
【问题描述】:

例如,对于 IoDevices,可以使用 io:getopts/1,但我找不到任何用于纯字符串的方法。

例如,

ManPage = os:cmd("man ls").           
%   [76,83,40,49,41,32,32,32,32,32,32,32,32,32,32,32,32,32,32,
%   32,32,32,32,32,32,32,32,32,32|...]

io:format("~p~n",[ManPage]).         
%   [76,83,40,49,41,(...)

io:format("~ts~n",[ManPage]).
%   LS(1)                   User Commands         LS(1)
%   NAME
%          ls - list directory contents

文档on using Unicode in Erlang 仅提及启发式方法,但它可能已过时,因为根据示例io_lib:format/2~ts 控制字符会产生utf-8 输出。用 Erlang 18.0 试试:

Bullet = "\x{2022}".
%   [8226]

io:format("~ts~n", [Bullet]).
%   •
%   ok
io:format("~ts~n", ["•"]).   
%   •
%   ok

io_lib:format("~ts~n", [Bullet]).
%   [[8226],"\n"]

我知道我可以使用 unicode:characters_to_binary/{1,2,3},因为它接受 latin1 或 utf8 编码的输入并输出 unicode 编码的输出,但我很好奇是否还有其他方法。

有趣的是,unicode:characters_to_binary/1 工作正常,而 unicode:characters_to_list/1 不能(或者我在滥用它)。

unicode:characters_to_binary(ManPage).                       
%   <<"LS(1)   User Commands   LS(1)\n\n\n\nNAME\n  "...>>

unicode:characters_to_list(ManPage).  
%   [76,83,40|...]

unicode:characters_to_list(ManPage, latin1).
%   {error,"LS(1)   User Commands  LS(1",
     [8208,10,32|...]}

【问题讨论】:

    标签: unicode encoding utf-8 erlang


    【解决方案1】:

    不幸的是,只有启发式方法可以确定字符编码。有一个简短的解释为什么here

    也就是说,在您上面指定的特定情况下,真正的问题是系统(而不是 Erlang)shell 设置为什么编码。我们可以通过直接检查环境来发现这一点(尽管这将是一个特定于平台的解决方案——我是从使用 Bash 的 Debian 派生系统编写的):

    1> LANG = os:cmd("echo $LANG").
    "ja_JP.UTF-8\n"
    2> {_, Enc} = lists:split(6, LANG).
    {"ja_JP.","UTF-8\n"}
    3> Encoding = string:strip(Enc, right, $\n).
    "UTF-8"
    

    然而,这是一个相当糟糕的解决方案。它完全不可移植,并且无法保证您的环境实际上遵循规则并将 5 个字符的语言/区域、然后是点、然后是编码放入其 $LANG 环境变量中。我很确定这不起作用,例如,至少在某些版本的 Solaris 上,在 AIX 上,我认为获得编码的方法是检查 $LC_CTYPE 或类似的东西(或者可能是倒退.. . 或者... 看,我什至不记得这个怪癖这一事实足以表明这是不可靠的)。

    另一种方法是使用locale 命令并让它直接为您提供字符集:

    4> os:cmd("locale charmap").
    "UTF-8\n"
    

    后面的换行符让我很烦,所以...

    5> string:strip(os:cmd("locale charmap"), right, $\n).
    "UTF-8"
    

    也就是说,locale 命令也并非无处不在。在任何情况下,从环境和环境变量中检查语言环境输出数据的某种组合应该可以解决问题,但要使其可移植,您需要用几种方法来武装您的系统。幸运的是大多数系统现在默认是utf8,除了Windows,但至少Windows是大部分内部标准化的。

    (如果您专门处理手册页...请记住,手册页中嵌入了用于标记的控制字符,因此虽然手册页的纯文本输出将是您所期望的,但实际的man 解释的联机帮助页数据已标记。根据您的操作,直接操作联机帮助页存档数据可能更容易。)

    【讨论】:

    • 我只是在玩 Yaws 的本地构建和文档页面上直接称为 man 的脚本。我认为结果的编码将由 shell 设置,但我希望有一个“懒惰”的解决方案。感谢您对环境变量的详细解释,因为到目前为止我只使用过其他 Linux 发行版而不是 unice。
    【解决方案2】:

    不清楚我们在说什么编程语言,但是没有这样的方法。

    您可能会要求用户设置环境变量 LC_ALL/LC_CTYPE/LANG 以匹配数据,但不能确定他们是否真的这样做了。

    此外,您的程序可能必须在同一程序运行中处理不同的编码(例如,来自不同的文件),因此您要么使用一些启发式方法来猜测编码(期待麻烦!),要么给用户一个方法指定编码——就像打开文件时的文本编辑器一样。

    【讨论】:

    • 原始问题包含“在 Erlang”中,但已被删除。我希望它有一个我不知道的其他语言没有的灵丹妙药(我知道这很天真,但我必须尝试)。
    猜你喜欢
    • 1970-01-01
    • 2016-02-07
    • 1970-01-01
    • 2016-08-14
    • 2020-11-28
    • 2011-02-19
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多