Erlang编码utf8转urlunicode(二)

时间:2022-06-01 17:46:14

Erlang里面utf8 == urlunicode,差别只是:tf8是10进制,转成16进制就是url

下面是把utf8转成url格式的方法:

%% utf8 -> urlunicode
utf8_to_url(Data) when is_binary(Data)->
    Data2 = [T || <<T:8>> <= Data],
    utf8_to_url(Data2, []);
utf8_to_url(Data) when is_list(Data)->
    utf8_to_url(Data, []).

utf8_to_url([], Url) -> Url;
utf8_to_url([Utf8Code | Tail], Url) ->
    NewUrl = Url ++ "%" ++ integer_to_list(Utf8Code, 16),
    utf8_to_url(Tail, NewUrl).

例子:

1> A = <<"汉字"/utf8>>.
<<230,177,137,229,173,151>>
2> util:utf8_to_url(A).
"%E6%B1%89%E5%AD%97"

注意:不管是二进制还是列表,里面的整数都要是utf8的,即范围 0~255

3> "汉字".
[27721,23383]

这种不可以直接转,需要先转成utf8。

7> A = "汉字".
[27721,23383]
8> unicode:characters_to_binary(A).
<<230,177,137,229,173,151>>
9> B = unicode:characters_to_binary(A).
<<230,177,137,229,173,151>>
10> util:utf8_to_url(B).
"%E6%B1%89%E5%AD%97"

中间经过了一步转换。
简单点的做法就是全部用二进制

<<String/utf8>>

PS

上面的方法只是为了理解编码,实际项目中不需要通过上面的方法完成。
Erlang里面url编码使用http_uri:encode/1
比如对

http://alidns.aliyuncs.com/?Format=XML&AccessKeyId=testid&Action=DescribeDomainRecords&SignatureMethod=HMAC-SHA1&DomainName=example.com&SignatureNonce=f59ed6a9-83fc-473b-9cc6-99c95df3856e&SignatureVersion=1.0&Version=2015-01-09&Timestamp=2016-03-24T16:41:54Z

?后面的部分进行编码:

1> Url1 = "Format=XML&AccessKeyId=testid&Action=DescribeDomainRecords&SignatureMethod=HMAC-SHA1&DomainName=example.com&SignatureNonce=f59ed6a9-83fc-473b-9cc6-99c95df3856e&SignatureVersion=1.0&Version=2015-01-09&Timestamp=2016-03-24T16:41:54Z".
... ...
2> http_uri:encode(Url1).
"Format%3DXML%26AccessKeyId%3Dtestid%26Action%3DDescribeDomainRecords%26SignatureMethod%3DHMAC-SHA1%26DomainName%3Dexample.com%26SignatureNonce%3Df59ed6a9-83fc-473b-9cc6-99c95df3856e%26SignatureVersion%3D1.0%26Version%3D2015-01-09%26Timestamp%3D2016-03-24T16%3A41%3A54Z"

再PS:汉字等编码


以上是 0~255,当超过255http_uri:encode/1就没办法处理。
官方有个edoc_lib.erl模块,里面的函数超过 255 可以处理,但结果是错误的。

例如:

标签 测试 进行编码

Eshell V8.3  (abort with ^G)
1> edoc_lib:escape_uri("标签 测试").
"%c0%87%c1%be%20%c1%8b%c3%95"

但其真实结果是:%E6%A0%87%E7%AD%BE%20%E6%B5%8B%E8%AF%95

  • 解决方案:

    -module(uri).
    
    -export([encode/1]).
    
    encode(S) when is_list(S) ->
        encode(unicode:characters_to_binary(S));
    encode(<<C, Cs/binary>>) when C >= $a, C =< $z ->
        [C] ++ encode(Cs);
    encode(<<C, Cs/binary>>) when C >= $A, C =< $Z ->
        [C] ++ encode(Cs);
    encode(<<C, Cs/binary>>) when C >= $0, C =< $9 ->
        [C] ++ encode(Cs);
    encode(<<C, Cs/binary>>) when C == $. ->
        [C] ++ encode(Cs);
    encode(<<C, Cs/binary>>) when C == $- ->
        [C] ++ encode(Cs);
    encode(<<C, Cs/binary>>) when C == $_ ->
        [C] ++ encode(Cs);
    encode(<<C, Cs/binary>>) ->
        escape_byte(C) ++ encode(Cs);
    encode(<<>>) ->
        "".
    
    escape_byte(C) ->
        "%" ++ hex_octet(C).
    
    hex_octet(N) when N =< 9 ->
        [$0 + N];
    hex_octet(N) when N > 15 ->
        hex_octet(N bsr 4) ++ hex_octet(N band 15);
    hex_octet(N) ->
        [N - 10 + $A].

    参考:
    URL encode in Erlang
    github.com/renatoalbano/3796470

Erlang编码utf8转urlunicode(二) 本文由 qingchuwudi 原创、整理,除非另有声明,本作品采用知识共享署名 3.0 *许可协议进行许可。