Erlang 从复杂的元组/列表结构创建有效的函数声明

Erlang 从复杂的元组/列表结构创建有效的函数声明,erlang,Erlang,在Erlang中给定一个复杂对象,除了查看它之外,还有没有一种通用的方法为它提供一个有效的函数声明?我正在维护一些以前由巨型结构的狂热爱好者编写的代码,事实证明,手动执行这些代码很容易出错。 我不需要重复整个过程,只需要抓住顶层本身 例如,我现在正在做这个- [[["SIP",47,"2",46,"0"],32,"407",32,"Proxy Authentication Required","\r\n"], [{'Via', [{'via-parm',

在Erlang中给定一个复杂对象,除了查看它之外,还有没有一种通用的方法为它提供一个有效的函数声明?我正在维护一些以前由巨型结构的狂热爱好者编写的代码,事实证明,手动执行这些代码很容易出错。 我不需要重复整个过程,只需要抓住顶层本身

例如,我现在正在做这个-

[[["SIP",47,"2",46,"0"],32,"407",32,"Proxy Authentication Required","\r\n"],
 [{'Via',
        [{'via-parm',
              {'sent-protocol',"SIP","2.0","UDP"},
              {'sent-by',"172.20.10.5","5060"},
              [{'via-branch',"z9hG4bKb561e4f03a40c4439ba375b2ac3c9f91.0"}]}]},
  {'Via',
        [{'via-parm',
              {'sent-protocol',"SIP","2.0","UDP"},
              {'sent-by',"172.20.10.15","5060"},
              [{'via-branch',"12dee0b2f48309f40b7857b9c73be9ac"}]}]},
  {'From',
        {'from-spec',
             {'name-addr',
                  [[]],
                  {'SIP-URI',
                        [{userinfo,{user,"003018CFE4EF"},[]}],
                        {hostport,"172.20.10.11",[]},
                        {'uri-parameters',[]},
                        []}},
             [{tag,"b7226ffa86c46af7bf6e32969ad16940"}]}},
  {'To',
        {'name-addr',
             [[]],
             {'SIP-URI',
                  [{userinfo,{user,"3966"},[]}],
                  {hostport,"172.20.10.11",[]},
                  {'uri-parameters',[]},
                  []}},
        [{tag,"a830c764"}]},
  {'Call-ID',"90df0e4968c9a4545a009b1adf268605@172.20.10.15"},
  {'CSeq',1358286,"SUBSCRIBE"},
  ["date",'HCOLON',
    ["Mon",44,32,["13",32,"Jun",32,"2011"],32,["17",58,"03",58,"55"],32,"GMT"]],
  {'Contact',
        [[{'name-addr',
                [[]],
                {'SIP-URI',
                     [{userinfo,{user,"3ComCallProcessor"},[]}],
                     {hostport,"172.20.10.11",[]},
                     {'uri-parameters',[]},
                     []}},
          []],
         []]},
  ["expires",'HCOLON',3600],
  ["user-agent",'HCOLON',
    ["3Com",[]],
    [['LWS',["VCX",[]]],
     ['LWS',["7210",[]]],
     ['LWS',["IP",[]]],
     ['LWS',["CallProcessor",[['SLASH',"v10.0.8"]]]]]],
  ["proxy-authenticate",'HCOLON',
    ["Digest",'LWS',
     ["realm",'EQUAL',['SWS',34,"3Com",34]],
     [['COMMA',["domain",'EQUAL',['SWS',34,"3Com",34]]],
      ['COMMA',
        ["nonce",'EQUAL',
         ['SWS',34,"btbvbsbzbBbAbwbybvbxbCbtbzbubqbubsbqbtbsbqbtbxbCbxbsbybs",
          34]]],
      ['COMMA',["stale",'EQUAL',"FALSE"]],
      ['COMMA',["algorithm",'EQUAL',"MD5"]]]]],
  {'Content-Length',0}],
 "\r\n",
 ["\n"]]

使用模式匹配和用于列表的函数仅提取您需要的内容

看看:
keyfind
keyreplace
L=[H | T]
,…

使用模式匹配和在列表上工作的函数,仅提取您需要的内容

看看:
keyfind
keyreplace
L=[H | T]
,…

也许

也许

如果我理解正确,您希望模式匹配一些未知格式的大型数据结构

例如:

Input: {a, b} {a,b,c,d} {a,[],{},{b,c}}

function({A, B}) -> do_something;
function({A, B, C, D}) when is_atom(B) -> do_something_else;
function({A, B, C, D}) when is_list(B) -> more_doing.
当然,一般的答案是,仅仅从数据就知道如何对数据进行分类是不可判定的

首先,你应该了解暴力分子。它们是由诸如io_lib:format/2之类的函数以及代码中的许多其他地方创建的

一个例子是

 [["SIP",47,"2",46,"0"],32,"407",32,"Proxy Authentication Required","\r\n"]
将打印为

 SIP/2.0 407 Proxy Authentication Required
所以,我首先要用一个函数,比如

 flatten_io(List) when is_list(List) ->
     Flat = lists:map(fun flatten_io/1, List),
     maybe_flatten(Flat);
 flatten_io(Tuple) when is_tuple(Tuple) ->
      list_to_tuple([flatten_io(Element) || Element <- tuple_to_list(Tuple)];
 flatten_io(Other) -> Other.

 maybe_flatten(L) when is_list(L) ->
      case lists:all(fun(Ch) when Ch > 0 andalso Ch < 256 -> true;
                   (List) when is_list(List) ->
                        lists:all(fun(X) -> X > 0 andalso X < 256 end, List);
                   (_) -> false
                end, L) of
          true -> lists:flatten(L);
          false -> L
      end.
is\u List(List)时展平io(List)->
平面=列表:地图(趣味平面io/1,列表),
也许你会变平(变平);
当“是”时展平io(元组)->
列出_到_元组([展平_io(元素)| |元素其他)。
当列表(L)->
案例列表:当Ch>0且Ch<256->true时的所有(乐趣(Ch);
什么时候是列表
列表:全部(乐趣(X)->X>0,并且X<256结束,列表);
())->错
完(L)
正确->列表:展平(L);
假->L
终止
(警告:完全未经测试且效率很低。InProperter列表也会崩溃,但无论如何,数据结构中都不应该有这些列表。)

再想一想,我帮不了你。任何在字符串中使用原子“逗号”作为逗号的数据结构都应该取出并拍摄

你也应该能够将这些东西展平,并开始了解你所看到的东西


我知道这不是一个完整的答案。希望能有所帮助。

如果我理解正确,您希望模式匹配一些未知格式的大型数据结构

例如:

Input: {a, b} {a,b,c,d} {a,[],{},{b,c}}

function({A, B}) -> do_something;
function({A, B, C, D}) when is_atom(B) -> do_something_else;
function({A, B, C, D}) when is_list(B) -> more_doing.
当然,一般的答案是,仅仅从数据就知道如何对数据进行分类是不可判定的

首先,您应该了解iolist,它们是由io_lib:format/2等函数以及代码中的许多其他地方创建的

一个例子是

 [["SIP",47,"2",46,"0"],32,"407",32,"Proxy Authentication Required","\r\n"]
将打印为

 SIP/2.0 407 Proxy Authentication Required
所以,我首先要用一个函数,比如

 flatten_io(List) when is_list(List) ->
     Flat = lists:map(fun flatten_io/1, List),
     maybe_flatten(Flat);
 flatten_io(Tuple) when is_tuple(Tuple) ->
      list_to_tuple([flatten_io(Element) || Element <- tuple_to_list(Tuple)];
 flatten_io(Other) -> Other.

 maybe_flatten(L) when is_list(L) ->
      case lists:all(fun(Ch) when Ch > 0 andalso Ch < 256 -> true;
                   (List) when is_list(List) ->
                        lists:all(fun(X) -> X > 0 andalso X < 256 end, List);
                   (_) -> false
                end, L) of
          true -> lists:flatten(L);
          false -> L
      end.
is\u List(List)时展平io(List)->
平面=列表:地图(趣味平面io/1,列表),
也许你会变平(变平);
当“是”时展平io(元组)->
列出_到_元组([展平_io(元素)| |元素其他)。
当列表(L)->
案例列表:当Ch>0且Ch<256->true时的所有(乐趣(Ch);
什么时候是列表
列表:全部(乐趣(X)->X>0,并且X<256结束,列表);
())->错
完(L)
正确->列表:展平(L);
假->L
终止
(警告:完全未经测试且效率很低。InProperter列表也会崩溃,但无论如何,数据结构中都不应该有这些列表。)

再想一想,我帮不了你。任何在字符串中使用原子“逗号”作为逗号的数据结构都应该取出并拍摄

你也应该能够将这些东西展平,并开始了解你所看到的东西


我知道这不是一个完整的答案。希望它能有所帮助。

很难推荐解决这个问题的方法

将所有结构转换为更合理、更精简的格式似乎是值得的。这主要取决于这些结构的相似性

与其为100个部件中的每一个都有一个特殊的功能,还不如进行一些自动重新格式化,甚至可以将部件记录下来

一旦你有了记录,为它编写函数就容易多了,因为你不需要知道记录中元素的实际数量。更重要的是:当元素数量发生变化时,你的代码不会中断

总而言之:通过尽可能使用最通用的代码对它们进行消毒,在你的代码和这些结构的疯狂之间设置一道屏障。这可能是通用的重新格式化与特定结构的混合

在这个结构中已经可以看到一个例子:
'name-addr'
元组看起来有一个统一的结构。所以你可以在你的结构上递归(在元组和列表的所有元素上),匹配具有类似
'name-addr'
的公共结构的“东西”,并用漂亮的记录替换它们

为了帮助您观察,您可以按照以下示例编写帮助器函数:

eyeball(List) when is_list(List) ->
    io:format("List with length ~b\n", [length(List)]);
eyeball(Tuple) when is_tuple(Tuple) ->
    io:format("Tuple with ~b elements\n", [tuple_size(Tuple)]).
因此,您将得到如下输出:

2> eyeball({a,b,c}).
Tuple with 3 elements
ok
3> eyeball([a,b,c]).
List with length 3
ok

在一个有用的工具中进行扩展供您使用,这只是一个练习。您可以通过在元素上递归并缩进输出来处理多个级别。

很难推荐处理此问题的方法

将所有结构转换为更合理、更精简的格式似乎是值得的。这主要取决于这些结构的相似性

与其为100个部件中的每一个都有一个特殊的功能,还不如进行一些自动重新格式化,甚至可以将部件记录下来

一旦你有了记录,为它编写函数就容易多了,因为你不需要