我正在尝试使用Erlang从PostgreSQL中获取数据。
这是我从DB获取数据的代码。但是我在'status'栏中有cyrrilic数据。这个cyrrilic数据没有正确获取。
我尝试使用UserInfo = io_lib:format("~tp ~n",[UserInfoQuery]),
,但这似乎不起作用,因为它会崩溃应用程序。
UserInfoQuery = odbc_queries:get_user_info(LServer,LUser),
UserInfo = io_lib:format("~p",[UserInfoQuery]),
?DEBUG("UserInfo: ~p",[UserInfo]),
StringForUserInfo = lists:flatten(UserInfo),
get_user_info(LServer, Id) ->
ejabberd_odbc:sql_query(
LServer,
[<<"select * from users "
"where email_hash='">>, Id, "';"]).
这是从DB
获取的数据{selected,[<<"username">>,<<"password">>,<<"created_at">>,
<<"id">>,<<"email_hash">>,<<"status">>],
[{<<"admin">>,<<"admin">>,<<"2014-05-13 12:40:30.757433">>,
<<"1">>,<<"adminhash">>,
<<209,139,209,132,208,178,208,176,209,139,209,132,208,
178,208,176>>}]}
问题:
其他问题:有没有办法以人类可读的格式获取字符串,以便来自RowUnicode的StringForUserInfo = 'ыфваыфва'
?
我试过这个:
{selected, _, [Row]} = UserInfoQuery,
RowUnicode = io_lib:format("~tp~n", [Row]),
?DEBUG("RowUnicode: ~p",[RowUnicode]),
StringForUserInfo = lists:flatten(RowUnicode),
错误:
bad argument in call to erlang:iolist_size([123,60,60,34,97,100,109,105,110,34,
62,62,44,60,60,34,97,100,109,105,110,34,62,62,44,60,60,34,50,...])
答案 0 :(得分:2)
Erlang ODBC驱动程序从数据库中完美地获取了状态列。实际上,PostgreSQL对您的数据进行编码是UTF-8,您获得的值是UTF-8编码。
Status = <<209,139,209,132,208,178,208,176,209,139,209,132,208,178,208,176>>.
这是一个表示UTF-8中字符串ыфваыфва
的二进制文件。
您可以在代码中直接使用UTF-8编码的二进制文件。如果要使用unicode字符点而不是UTF-8字节,可以将其转换为整数列表(Erlang用语中的字符串)。只需使用unicode:characters_to_list/1
,在您的情况下将生成列表[1099,1092,1074,1072,1099,1092,1074,1072]
。这是相同字符串的列表表示。 Unicode字符1099(十六进制为16#044B)是ы(CYRILLIC SMALL LETTER YERU,cf Cyrillic excerpt unicode chart)。
Erlang可以在上面的两个表示中处理unicode文本:unicode字符列表作为整数和UTF-8编码字符的二进制文件。
让我们来看一个较小的例子,字符串"ы"
。该字符串由unicode字符044B CYRILLIC SMALL LETTER YERU组成,可以编码为<<209,139>>
的二进制文件或[16#044B]
(= [1099]
)的列表。
历史上,整数列表和二进制文件都是Latin-1(ISO-8859-1)编码。 Unicode和ISO-8859-1具有0到255之间相同的值,但UTF-8转换仅匹配0-127范围内字符的ISO-8859-1。出于这个原因,Erlang的~s
格式参数有一个unicode转换修饰符~ts
。以下行将无法按预期工作:
io:format("~s", [<<209,139>>]).
它将输出两个字符,00D1(LATIN CAPITAL LETTER N WITH TILDE)和008B(PARTIAL LINE FORWARD)。这是因为&lt;&lt;&lt;&lt;&lt;&nbsp;&gt;&gt;&gt;被解释为Latin-1字符串而不是UTF-8编码字符串。
以下行将失败:
io:format("~s", [[1099]]).
这是因为[1099]不是有效的Latin-1字符串。
相反,你应该写:
io:format("~ts", [<<209,139>>]),
io:format("~ts", [[1099]]).
Erlang的~p
格式参数也有一个unicode翻译修饰符~tp
。但是,~tp
将不会执行您正在寻找单独的内容。无论您使用~p
还是~tp
,默认情况下,io_lib:format/2
都会将上面的状态UTF-8编码二进制格式设置为:
<<209,139,209,132,208,178,208,176,209,139,209,132,208,178,208,176>>
实际上,t
修饰符仅表示参数应接受unicode输入。如果您使用~p
,在格式化字符串或二进制文件时,Erlang将确定是否可以将其表示为Latin-1字符串,因为输入可能是Latin-1编码。这种启发式方法允许Erlang在大多数情况下正确区分整数和字符串列表。要查看工作中的启发式,您可以尝试以下方法:
io:format("~p\n~p\n", [[69,114,108,97,110,103], [1,2,3,4,5,6]]).
启发式检测到[69,114,108,97,110,103]
实际上是"Erlang"
,而[1,2,3,4,5,6]
只是一个整数列表。
如果你使用~tp
,Erlang会希望字符串或二进制文件是unicode编码的,然后应用默认标识启发式。目前默认的启发式(R17)也是latin-1。由于您的字符串无法用Latin-1表示,因此Erlang会将其显示为整数列表。幸运的是,您可以通过在命令行上将+pc unicode
传递给Erlang来切换到Unicode启发式算法,这将产生您正在寻找的内容。
$ erl +pc unicode
因此,解决问题的方法是通过+pc unicode
并使用~tp
。
答案 1 :(得分:1)
我不明白为什么io:format("~tp")
不起作用,但您可以提取所需的行和列,并使用io:format("~ts")
进行打印:
> {selected, _, [Row]} = UserInfoQuery.
> io:format("~ts~n", [element(6, Row)]).
ыфваыфва
ok