动态模式匹配

时间:2010-10-21 15:44:11

标签: erlang pattern-matching

如何在Erlang中进行动态模式匹配?

我有功能过滤器/ 2:

filter(Pattern, Array)

其中Pattern是一个字符串,其中包含我想要匹配的模式(例如"{book, _ }""{ebook, _ }")用户输入,而Array是异构元素的数组(例如{dvd, "The Godfather" } , {book, "The Hitchhiker's Guide to the Galaxy" }, {dvd, "The Lord of Rings"}等) )然后我想上面的filter / 2返回Array中与Pattern匹配的元素数组。

我已经尝试了erl_eval一些没有任何成功的想法......

事先提前。

4 个答案:

答案 0 :(得分:5)

进行一点文档研究:

Eval = fun(S) -> {ok, T, _} = erl_scan:string(S), {ok,[A]} = erl_parse:parse_exprs(T), {value, V, _} = erl_eval:expr(A,[]), V end,
FilterGen = fun(X) -> Eval(lists:flatten(["fun(",X,")->true;(_)->false end."])) end,
filter(FilterGen("{book, _}"), [{dvd, "The Godfather" } , {book, "The Hitchhiker's Guide to the Galaxy" }, {dvd, "The Lord of Rings"}]).
[{book,"The Hitchhiker's Guide to the Galaxy"}]

答案 1 :(得分:2)

为什么你想要一个字符串中的模式有什么特殊原因?

Erlang中不存在这样的模式,它们实际上只能出现在代码中。另一种方法是使用与ETS matchselect相同的约定,并编写自己的匹配函数。这真的很简单。 ETS约定使用一个术语来表示一种模式,其中原子'$1''$2'等用作可以绑定和测试的变量,'_'是无关变量。因此,您的示例模式将成为:

{book,'_'}
{ebook,'_'}
{dvd,"The Godfather"}

这可能是最有效的方法。这里有可能使用匹配规范,但会使代码复杂化。这取决于你需要多么复杂的匹配。

修改 我添加了没有注释代码的部分匹配器:

%% match(Pattern, Value) -> {yes,Bindings} | no.

match(Pat, Val) ->
    match(Pat, Val, orddict:new()).

match([H|T], [V|Vs], Bs0) ->
    case match(H, V, Bs0) of
        {yes,Bs1} -> match(T, Vs, Bs1);
        no -> no
    end;
match('_', _, Bs) -> {yes,Bs};                  %Don't care variable
match(P, V, Bs) when is_atom(P) ->
    case is_variable(P) of
        true -> match_var(P, V, Bs);            %Variable atom like '$1'
        false ->
            %% P just an atom.
            if P =:= V -> {yes,Bs};
               true -> no
            end
    end.

match_var(P, V, Bs) ->
    case orddict:find(P, Bs) of
        {ok,B} when B =:= V -> {yes,Bs};
        {ok,_} -> no;
        error -> {yes,orddict:store(P, V, Bs)}
    end.

答案 2 :(得分:0)

您可以使用lists:filter/2来执行过滤部分。将字符串转换为代码是另一回事。所有模式都是{atom, _}的形式吗?如果是这样,您可以存储原子并将其传递给列表的闭包参数:filter。

答案 3 :(得分:0)

有几种可能性出现在脑海中,具体取决于模式的动态程度以及模式中需要的功能:

  1. 如果您需要完全符合erlang模式的语法,则模式不会经常更改。您可以创建匹配的源代码并将其写入文件。使用compile:file创建二进制文件并使用code:load_binary加载。

    • 优势:非常快速匹配

    • 缺点:模式更改时的开销

  2. 将数据从Array填入ETS并使用match specifications获取数据

    • 您可以使用fun2ms来帮助创建匹配规范。但fun2ms通常在编译期间用作解析转换。 shell还使用了一种模式,可以在解析器的帮助下从字符串开始工作。有关详细信息,请参阅ms_transform
  3. 可能还有某种方法可以使用qlc,但我没有详细研究过。

  4. 在任何情况下,如果来自不受信任的来源,请小心清理匹配数据!