经验首页 前端设计 程序设计 Java相关 移动开发 数据库/运维 软件/图像 大数据/云计算 其他经验
当前位置:技术经验 » 程序设计 » Erlang » 查看文章
Erlang 进制转换 - 雄霸天下-无人能挡
来源:cnblogs  作者:雄霸天下-无人能挡  时间:2019/8/15 12:42:11  对本文有异议

文章转载自:http://www.pythonheidong.com/blog/article/2987/

http://www.cnblogs.com/me-sa/archive/2012/03/20/erlang0047.html

bnot unary bitwise not integer
div integer division integer
rem integer remainder of X/Y integer
band bitwise and integer
bor bitwise or integer
bxor arithmetic bitwise xor integer
bsl arithmetic bitshift left integer
bsr bitshift right integer
去年读过的好书之一就是这本《编码:隐匿在计算机软硬件背后的语言》(豆瓣链接 )里面对进制有一段非常有意思的描述:
    如果人类像卡通人物那样,每只手上只有 4个手指会怎样呢?我们可能永远都不会想到要发明一种以10为基础的数字系统的问题, 取而代之的是我们可能会认为数字系统基于 8是正常、自然、合理、必然的,是毫无疑问的,是非常合适的。这时,就不能称之为十进制了,得将它称作为以8为基础的数字系统或八进制。
... ...
龙虾根本没有手指,但它两只前爪的末端都有螯。适合于龙虾的数字系统是四进制数字系统或称为基于4的数字系统.

 
 
   我们平常编程经常会遇到进制转换的问题,有时候是为了把机器可处理的转换成人类可读的,有时候是把人类可读的转成机器可处理的;有时候是把一台机器可处理的转成另外一台机器可以处理的;进制转换几乎是所有开发者的公共话题,这个问题也经常作为面试题出现......有中枪的么?
    
 在.net中,做进制转换可以使用Convert.ToInt32(String,Base)做 2, 8, 10, 16进制之间的转换:
     Convert.ToInt32("10101010",2);  Convert.ToInt32("12",16);
Convert.ToInt32 Method (String, Int32) 
The base of the number in value, which must be 2, 8, 10, or 16. 
Converts the string representation of a number in a specified base to an equivalent 32-bit signed integer.

Erlang

 Erlang中进行进制转换是比较方便的,首先在Shell中可以通过Base#Number的形式计算各种进制对应的十进制数值;
复制代码
  1. Eshell V5.9 (abort with ^G)
    1> 2#1011.
    11
    2> 2#1111.
    15
    3> 16#12.
    18
    4> 16#1F.
    31
    5> 8#121.
    81
    6> 7#11.
    8
    7>
复制代码
 Erlang BIF 提供了两个基础方法方便从十进制数值转到各种进制字符串,以及其逆过程,目前支持的进制是2到36:
复制代码
  1. Eshell V5.9 (abort with ^G)
    1> integer_to_list(1234,8).
    "2322"
    2> integer_to_list(1234,16).
    "4D2"
    3> list_to_integer("2322",8).
    1234
    4> list_to_integer("4d2",16).
    1234
复制代码

integer_to_list(Integer, Base) -> string()

Types:

Integer = integer()
Base = 2..36

Returns a string which corresponds to the text representation of Integer in base Base.

list_to_integer(String, Base) -> integer()

Types:

String = string()
Base = 2..36
Returns an integer whose text representation in base Base is String.

    群里面有人问如何把"abc"转换成 "110000111000101100011"的形式,即逐字符转成二进制,不管他转成这样的格式做什么用,实现起来还是比较简单的:lists:concat([erlang:integer_to_list(Item,2) || Item<-"abc"  ]).
 
这里看下从十进制到其它进制转换是怎么实现的,这是一个通用的方法:
复制代码
  1. %%Code Path:\erl5.9\lib\erts-5.9\src\erlang.erl
    integer_to_list(I0, Base, R0) ->
    D = I0 rem Base,
    I1 = I0 div Base,
    R1 = if D >= 10 ->
    [D-10+$A|R0];
    true ->
    [D+$0|R0]
    end,
    if I1 =:= 0 ->
    R1;
    true ->
    integer_to_list(I1, Base, R1)
    end.
复制代码
   上面是一个通用的处理方法;对于一些特例的情况,比如十进制转到16进制的情况,可以通过移位和逻辑运算完成:4bit的最大值是15 (2#1111) ,N band 15 获得最后四位的值,不断进行右移4位和band操作就可以完成10进制到16进制的转换;
复制代码
  1. %% @spec hexdigit(integer()) -> char()
    %% @doc Convert an integer less than 16 to a hex digit.
    hexdigit(C) when C >= 0, C =< 9 ->
    C + $0;
    hexdigit(C) when C =< 15 ->
    C + $a - 10.


    to_hex_int(0, Acc) ->
    Acc;
    to_hex_int(I, Acc) ->
    to_hex_int(I bsr 4, [hexdigit(I band 15) | Acc]).
复制代码
  同样的思路,可以完成10进制到2进制的转换,以及10进制到8进制的转换:
复制代码
  1. de2bin(0,Acc)->
    Acc;
    de2bin(N,Acc) ->
    de2bin(N bsr 1,[((N band 1)+$0)|Acc]).

    de2oct(0,Acc) ->
    Acc;
    de2oct(N,Acc) ->
    de2oct(N bsr 3 ,[((N band 7)+$0)|Acc]).
复制代码
 看下调用的效果:
复制代码
  1. Eshell V5.9 (abort with ^G)
    1> zen:de2oct(1234,[]).
    "2322"
    2> 8#2322.
    1234
    3> zen:de2oct(1,[]).
    "1"
    4> zen:de2bin(1234,[]).
    "10011010010"
    5> list_to_integer(zen:de2oct(1234,[]),8).
    1234
    6>
复制代码
Erlang开源项目mochiweb包含了一个处理十六进制数据的模块,(下面的代码我按照调用关系调整了一下):
复制代码
  1. %% @author Bob Ippolito <bob@mochimedia.com>
    %% @copyright 2006 Mochi Media, Inc.

    %% @doc Utilities for working with hexadecimal strings.

    -module(mochihex).
    -author('bob@mochimedia.com').

    -export([test/0, to_hex/1, to_bin/1, to_int/1, dehex/1, hexdigit/1]).

    %% @type iolist() = [char() | binary() | iolist()]
    %% @type iodata() = iolist() | binary()

    %% @spec to_hex(integer | iolist()) -> string()
    %% @doc Convert an iolist to a hexadecimal string.
    to_hex(0) ->
    "0";
    to_hex(I) when is_integer(I), I > 0 ->
    to_hex_int(I, []);
    to_hex(B) ->
    to_hex(iolist_to_binary(B), []).

    to_hex(<<>>, Acc) ->
    lists:reverse(Acc);
    to_hex(<<C1:4, C2:4, Rest/binary>>, Acc) ->
    to_hex(Rest, [hexdigit(C2), hexdigit(C1) | Acc]).


    %% @spec hexdigit(integer()) -> char()
    %% @doc Convert an integer less than 16 to a hex digit.
    hexdigit(C) when C >= 0, C =< 9 ->
    C + $0;
    hexdigit(C) when C =< 15 ->
    C + $a - 10.


    to_hex_int(0, Acc) ->
    Acc;
    to_hex_int(I, Acc) ->
    to_hex_int(I bsr 4, [hexdigit(I band 15) | Acc]).



    %% @spec to_bin(string()) -> binary()
    %% @doc Convert a hexadecimal string to a binary.
    to_bin(L) ->
    to_bin(L, []).

    to_bin([], Acc) ->
    iolist_to_binary(lists:reverse(Acc));
    to_bin([C1, C2 | Rest], Acc) ->
    to_bin(Rest, [(dehex(C1) bsl 4) bor dehex(C2) | Acc]).

    %% @spec dehex(char()) -> integer()
    %% @doc Convert a hex digit to its integer value.
    dehex(C) when C >= $0, C =< $9 ->
    C - $0;
    dehex(C) when C >= $a, C =< $f ->
    C - $a + 10;
    dehex(C) when C >= $A, C =< $F ->
    C - $A + 10.


    %% @spec to_int(string()) -> integer()
    %% @doc Convert a hexadecimal string to an integer.
    to_int(L) ->
    erlang:list_to_integer(L, 16).


    %% @spec test() -> ok
    %% @doc Test this module.
    test() ->
    "ff000ff1" = to_hex([255, 0, 15, 241]),
    <<255, 0, 15, 241>> = to_bin("ff000ff1"),
    16#ff000ff1 = to_int("ff000ff1"),
    "ff000ff1" = to_hex(16#ff000ff1),
    ok.
复制代码
 二进制数据处理代码段:
复制代码
  1. hexdigit(C) when C < 10 -> $0 + C;
  2. hexdigit(C) when C < 16 -> $A + (C - 10).
  3.  
  4. unhexdigit(C) when C >= $0, C =< $9 -> C - $0;
  5. unhexdigit(C) when C >= $a, C =< $f -> C - $a + 10;
  6. unhexdigit(C) when C >= $A, C =< $F -> C - $A + 10.
  7.  
  8. quote_plus([], Acc) ->
  9. lists:reverse(Acc);
  10. quote_plus([C | Rest], Acc) when ?QS_SAFE(C) ->
  11. quote_plus(Rest, [C | Acc]);
  12. quote_plus([$\s | Rest], Acc) ->
  13. quote_plus(Rest, [$+ | Acc]);
  14. quote_plus([C | Rest], Acc) ->
  15. <<Hi:4, Lo:4>> = <<C>>,
  16. quote_plus(Rest, [hexdigit(Lo), hexdigit(Hi), ?PERCENT | Acc]).
  17.  
  18. qs_revdecode(S) ->
  19. qs_revdecode(S, []).
  20.  
  21. qs_revdecode([], Acc) ->
  22. Acc;
  23. qs_revdecode([$+ | Rest], Acc) ->
  24. qs_revdecode(Rest, [$\s | Acc]);
  25. qs_revdecode([Lo, Hi, ?PERCENT | Rest], Acc) when ?IS_HEX(Lo), ?IS_HEX(Hi) ->
  26. qs_revdecode(Rest, [(unhexdigit(Lo) bor (unhexdigit(Hi) bsl 4)) | Acc]);
  27. qs_revdecode([C | Rest], Acc) ->
  28. qs_revdecode(Rest, [C | Acc]).
复制代码

 

 IP地址和整形互转

还有一个常见的问题就是IP地址到整形的互相转换,也可以按照同样的思路如法炮制:
首先,我们先确定一些常量的值:
复制代码
  1. 4> integer_to_list(16711680,2).
  2. "11111111,00000000,00000000"
  3. 6> integer_to_list(65280,2).
  4. "1111111100000000"
  5. 7> integer_to_list(16777216,2).
  6. "1000000000000000000000000"
  7. 8> integer_to_list(65536,2).
  8. "10000000000000000"
  9. 9> integer_to_list(256,2).
  10. "100000000"
复制代码
现在可以做转换了:
复制代码
  1. 10> Ip_to_integer=fun({A,B,C,D}) -> (A*16777216)+(B*65536)+(C*256)+D end.
  2. #Fun<erl_eval.6.111823515>
  3. 11> Ip_to_integer({192,168,0,188}).
  4. 3232235708
  5. 12> Integer_to_ip=fun(Ip)-> {Ip bsr 24, (Ip band 16711680) bsr 16, (Ip band 65280) bsr 8, Ip band 255} end.
  6. #Fun<erl_eval.6.111823515>
  7. 14> Integer_to_ip(3232235708).
  8. {192,168,0,188}
复制代码

 附:

bnot unary bitwise not integer
div integer division integer
rem integer remainder of X/Y integer
band bitwise and integer
bor bitwise or integer
bxor arithmetic bitwise xor integer
bsl arithmetic bitshift left integer
bsr bitshift right integer
 
 
P.S 有人问到列表解析的用法,这个可以看下官方文档:http://www.erlang.org/doc/programming_examples/list_comprehensions.html
列表解析很强大的说,看下面的例子
  1. sort([Pivot|T]) ->
    sort([ X || X <- T, X < Pivot]) ++
    [Pivot] ++
    sort([ X || X <- T, X >= Pivot]);
    sort([]) -> [].
上面是用两行代码实现了快速排序,在看一个实现全排列的
  1. perms([]) -> [[]];
    perms(L) -> [[H|T] || H <- L, T <- perms(L--[H])].
勾股定理数
复制代码
  1. pyth(N) ->
    [ {A,B,C} ||
    A <- lists:seq(1,N),
    B <- lists:seq(1,N),
    C <- lists:seq(1,N),
    A+B+C =< N,
    A*A+B*B == C*C
    ].

    %%优化版本
    pyth1(N) ->
    [{A,B,C} ||
    A <- lists:seq(1,N-2),
    B <- lists:seq(A+1,N-1),
    C <- lists:seq(B+1,N),
    A+B+C =< N,
    A*A+B*B == C*C ].
复制代码
 
另外列表解析可以在Erlang Shell中方便的实现for循环和if
复制代码
  1. 12> [io:format("abc")|| _<-lists:seq(1,10)].
    abcabcabcabcabcabcabcabcabcabc[ok,ok,ok,ok,ok,ok,ok,ok,ok,ok]
    13> E=34.
    34
    14> [io:format("abc")|| E>35].
    []
    15> [io:format("abc")|| E>32].
    abc[ok]
    16>
复制代码

文章转载自:http://www.pythonheidong.com/blog/article/2987/

原文链接:http://www.cnblogs.com/xiongbatianxiaskjdskjdksjdskdtuti/p/11356384.html

 友情链接:直通硅谷  点职佳  北美留学生论坛

本站QQ群:前端 618073944 | Java 606181507 | Python 626812652 | C/C++ 612253063 | 微信 634508462 | 苹果 692586424 | C#/.net 182808419 | PHP 305140648 | 运维 608723728

W3xue 的所有内容仅供测试,对任何法律问题及风险不承担任何责任。通过使用本站内容随之而来的风险与本站无关。
关于我们  |  意见建议  |  捐助我们  |  报错有奖  |  广告合作、友情链接(目前9元/月)请联系QQ:27243702 沸活量
皖ICP备17017327号-2 皖公网安备34020702000426号