erlang 中文编码显示乱码问题
许久没做erlang开发了,近期有网友问到erlang的问题。就抽时间看下。问题是这种。模块有中文。将中文直接打印出来。shell下显示会出现乱码。但假设先将中文转成binary。就行正常显示出来。
shell中文乱码问题
这里以一个简单的样例,说明下:
-module(m).
-compile(export_all). test() ->
io:format("~ts~n", ["中国"]),
io:format("~ts~n", [list_to_binary("中国")]).
以R17之前的erlang版本号编译。然后測试下结果:
Eshell V5.10.3 (abort with ^G)
1> c(m).
{ok, m}
2> m:test().
ä¸å½
中国
ok
{function, test, 0, 2}.
{label,1}.
{line,[{location,"erl.erl",4}]}.
{func_info,{atom,erl},{atom,test},0}.
{label,2}.
{allocate,0,0}.
{move,{literal,[[228,184,173,229,155,189]]},{x,1}}.
{move,{literal,"~ts~n"},{x,0}}.
{line,[{location,"erl.erl",5}]}.
{call_ext,2,{extfunc,io,format,2}}.
{move,{literal,[<<228,184,173,229,155,189>>]},{x,1}}.
{move,{literal,"~ts~n"},{x,0}}.
{line,[{location,"erl.erl",6}]}.
{call_ext_last,2,{extfunc,io,format,2},0}.
实际上,erlang在编译代码时会做优化。数据已知的话。list_to_binary在编译期就被优化掉了。
test() ->
io:format("~ts~n", [[228,184,173,229,155,189]]),
io:format("~ts~n", [<<228,184,173,229,155,189>>]).
io:format/2 对中文的处理
看了 io:format/2 的实现代码,关键代码为下面两步:
3> L = io_lib:format("~ts",[<<228,184,173,229,155,189>>]).
[[20013,22269]]
4> io:put_chars(L).
中国ok
%% io_lib.erl format(Format, Args) ->
case catch io_lib_format:fwrite(Format, Args) of
{'EXIT',_} ->
erlang:error(badarg, [Format, Args]);
Other ->
Other
end.
实现代码在 io_lib_format模块,例如以下:
%% io_lib_format.erl fwrite(Format, Args) when is_atom(Format) ->
fwrite(atom_to_list(Format), Args);
fwrite(Format, Args) when is_binary(Format) ->
fwrite(binary_to_list(Format), Args);
fwrite(Format, Args) ->
Cs = collect(Format, Args), %% 收集格式化信息。生成控制结构
Pc = pcount(Cs), %% 计算请求打印的数量
build(Cs, Pc, 0). %% 解析控制结构,生成数据 collect([$~|Fmt0], Args0) -> %% 格式化參数以 ~打头,否则忽略
{C,Fmt1,Args1} = collect_cseq(Fmt0, Args0),
[C|collect(Fmt1, Args1)];
collect([C|Fmt], Args) ->
[C|collect(Fmt, Args)];
collect([], []) -> []. collect_cseq(Fmt0, Args0) ->
{F,Ad,Fmt1,Args1} = field_width(Fmt0, Args0),
{P,Fmt2,Args2} = precision(Fmt1, Args1),
{Pad,Fmt3,Args3} = pad_char(Fmt2, Args2),
{Encoding,Fmt4,Args4} = encoding(Fmt3, Args3),
{Strings,Fmt5,Args5} = strings(Fmt4, Args4),
{C,As,Fmt6,Args6} = collect_cc(Fmt5, Args5),
{{C,As,F,Ad,P,Pad,Encoding,Strings},Fmt6,Args6}. %% 检查format 參数含有 t, 然后打标记 unicode。其它记latin1
encoding([$t|Fmt],Args) ->
true = hd(Fmt) =/= $l, %% 确保不是传入 ~tl
{unicode,Fmt,Args};
encoding(Fmt,Args) ->
{latin1,Fmt,Args}.
再看下以上build部分的代码。代码过长,做了删节:
%% io_lib_format.erl
build([{C,As,F,Ad,P,Pad,Enc,Str}|Cs], Pc0, I) ->
S = control(C, As, F, Ad, P, Pad, Enc, Str, I), %% 处理控制结构
Pc1 = decr_pc(C, Pc0),
if
Pc1 > 0 -> [S|build(Cs, Pc1, indentation(S, I))];
true -> [S|build(Cs, Pc1, I)]
end;
build([$\n|Cs], Pc, _I) -> [$\n|build(Cs, Pc, 0)];
build([$\t|Cs], Pc, I) -> [$\t|build(Cs, Pc, ((I + 8) div 8) * 8)];
build([C|Cs], Pc, I) -> [C|build(Cs, Pc, I+1)];
build([], _Pc, _I) -> [].
control($w, [A], F, Adj, P, Pad, _Enc, _Str, _I) ->
term(io_lib:write(A, -1), F, Adj, P, Pad);
control($p, [A], F, Adj, P, Pad, Enc, Str, I) ->
print(A, -1, F, Adj, P, Pad, Enc, Str, I);
control($W, [A,Depth], F, Adj, P, Pad, _Enc, _Str, _I) when is_integer(Depth) ->
term(io_lib:write(A, Depth), F, Adj, P, Pad);
control($P, [A,Depth], F, Adj, P, Pad, Enc, Str, I) when is_integer(Depth) ->
print(A, Depth, F, Adj, P, Pad, Enc, Str, I);
control($s, [A], F, Adj, P, Pad, _Enc, _Str, _I) when is_atom(A) ->
string(atom_to_list(A), F, Adj, P, Pad);
control($s, [L0], F, Adj, P, Pad, latin1, _Str, _I) -> %% 处理 ~s,假设数据标记是 latin1
L = iolist_to_chars(L0),
string(L, F, Adj, P, Pad);
control($s, [L0], F, Adj, P, Pad, unicode, _Str, _I) -> %% 处理 ~s,假设数据标记是 unicode
L = cdata_to_chars(L0),
uniconv(string(L, F, Adj, P, Pad));
control($e, [A], F, Adj, P, Pad, _Enc, _Str, _I) when is_float(A) ->
%% 该函数太长了,不是讨论重点,做了删节
cdata_to_chars([C|Cs]) when is_integer(C), C >= $\000 ->
[C | cdata_to_chars(Cs)];
cdata_to_chars([I|Cs]) ->
[cdata_to_chars(I) | cdata_to_chars(Cs)];
cdata_to_chars([]) ->
[];
cdata_to_chars(B) when is_binary(B) -> %% 假设数据是binary,做一下unicode转换
case catch unicode:characters_to_list(B) of
L when is_list(L) -> L;
_ -> binary_to_list(B)
end.
可想而知。假设没有不是 ~ts。或者不是binary。都不会做转换。
探讨乱码问题
可是,对于拓展字符集每一个语种都有自己的定义方式,相同一段字符数据用不同的字符集就有不同的解释。
这就是乱码出现的原因。
假设原文以utf8记录。显示的时候又以utf8表示,就能正常显示。
正是这样。io_lib:format/2 也对编码做了特殊处理,但也局限于前面所述的情况。
直到R17后,erlang才将utf8做为源码的默认编码,在这之前。源码都以latin1形式读取和编译的。R17假设想改变默认编码,方法就是在模块首行加 %% coding: latin-1
utf8_list_to_string(List) ->
unicode:characters_to_list(list_to_binary(List)).
那读写utf8文件呢,怎么避免出现乱码呢?
read_and_write() ->
{ok,Bin} = file:read_file("file.txt"),
MyList = case unicode:characters_to_list(Bin) of
L when is_list(L) -> L;
_ -> binary_to_list(Bin)
end,
{ok,G} = file:open("new_file.txt",[write,{encoding,utf8}]),
io:put_chars(G,MyList),
file:close(G).
好久没搞erlang了。突然心血来潮,写了这篇文章。希望喜欢。
參考:
erlang 中文编码显示乱码问题的更多相关文章
- 【原创】python中文编码问题深入分析(二):print打印中文异常及显示乱码问题分析与解决
在学习python以及在使用python进行项目开发的过程中,经常会使用print语句打印一些调试信息,这些调试信息中往往会包含中文,如果你使用python版本是python2.7,或许你也会遇到和我 ...
- pycharm的console显示乱码和中文的配置
第一种方式: 在python脚本开始的地方加入指定编码方式 # -*- coding : UTF-8 -*- 第二种方式: 有些时候我们会得到这种格式的字符串: "name": & ...
- 关于PHP页面显示乱码问题的解决
关于PHP页面显示乱码问题的解决 网页乱码一直是网络编程高手都头痛的问题,我是一个PHP Web编程的初学者,学习当中也遇到了这个问题,查找了相关的资源,总结如下: 一般的中文编码:gb2312,gb ...
- Linux中文显示乱码?如何设置centos显示中文
Linux中文显示乱码?如何设置centos显示中文 怎么设置Linux系统中文语言,这是很多小伙伴在开始使用Linux的时候,都会遇到一个问题,就是终端输入命令回显的时候中文显示乱码.出现这个情况一 ...
- linux终端 字符界面 显示乱码
方法一:配置SSH工具 SecureCRT中文版配置 [全局选项]→[默认会话]→[编辑默认设置]→[终端]→[外观]→[字体]→[新宋体 10pt CHINESE_GB2312]→[字符编码 UTF ...
- 下载apk文件浏览器会直接打开并显示乱码的问题
今天同事反映他的apk文件在自己的老项目中下载有问题:下载apk文件浏览器会直接打开并显示乱码,在别的项目中就没有问题. 后分析response的content-type发现,老项目的类型是text/ ...
- Xshell个性化设置,解决Xshell遇到中文显示乱码的问题
在同事的推荐下,今天开始使用Xshell连接Linux,但是发现一个“遇到中文显示乱码”的问题, 同事的解决方案如下: 平常给Linux上传文件之前,先把文件转换成UTF-8编码形式, 然后设置Xsh ...
- (转)sqlplus中文显示乱码的问题
sqlplus中文显示乱码的问题 2010-07-19 11:33:26 分类: LINUX 在windows下sqlplus完全正常,可是到linux下,sqlplus中文显示就出问题了,总是显示“ ...
- mysql 乱码问题(程序界面显示正常,mysql command line显示乱码)
今天用java写一个程序,用的是mysql数据库.界面出现乱码,然后写了一个过滤器结果了乱码问题. 但是,当我在mysql command line 中查询数据的时候,在界面上显示正常的数据,在mys ...
随机推荐
- bluej
他山之石,可以攻玉!吾辈之道,披荆斩棘! 个人源码地址: https://gitee.com/blue_phantom
- 【02】[].slice和Array.prototype.slice
[02][].slice和Array.prototype.slice 01,Array是一个构造函数.浏览器内置的特殊对象. 02,Array没有slice方法. 03,Array.prototy ...
- c#笔记2018-12-27
using System; /*2018-12-27 c#学习笔记 * 1.c#判断if /else if /switch * 2.循环while/for/do-while * 3.循环实例: for ...
- 【LeetCode】String to Integer (atoi)(字符串转换整数 (atoi))
这道题是LeetCode里的第8道题. 题目要求: 请你来实现一个 atoi 函数,使其能将字符串转换成整数. 首先,该函数会根据需要丢弃无用的开头空格字符,直到寻找到第一个非空格的字符为止. 当我们 ...
- CodeForces contest/776 A+B+C题解
ICM Technex 2017 and Codeforces Round #400 (Div. 1 +Div.2,combined) A. A Serial Killer 谜一样的题意:每天从两个人 ...
- n&(n-1)的用途
最近做LeetCode上面的题目,发现很多题目都用到了n&(n-1).感觉真是神通广大,下面就目前所看到的一些用途总结一下: 1,求一个int类型数是否为2的幂 当n=4时,二进制为:0100 ...
- cf575A Fibonotci
Fibonotci sequence is an integer recursive sequence defined by the recurrence relation Fn = sn - 1·F ...
- R语言入门视频笔记--5--自定义函数
自定义函数 你可以输出一段代码,创建一个你自己定义的函数 蛋是如果你两个自定义函数的名字重复的话,后面的会把前面的替换掉 举个栗子: hanshu1 <- function(x) sqrt(v ...
- Spring注解处理Ajax请求-JSON格式[系统架构:Spring+SpringMVC+MyBatis+MySql]
1.前端jsp页面 <div class="tab_tip"> 请输入[身份证号或姓名] <input type="text" class=& ...
- hdu 1827 有向图缩点看度数
题意:给一个有向图,选最少的点(同时最小价值),从这些点出发可以遍历所有. 思路:先有向图缩点,成有向树,找入度为0的点即可. 下面给出有向图缩点方法: 用一个数组SCC记录即可,重新编号,1.... ...