使用列表递归管道到函数

时间:2015-10-10 15:50:58

标签: elixir

我需要通过函数管道一个字符串列表来返回一个字符串。目前,我有这个:

@tag_delimiters [" ", "(", ".", "#"]

def tag(string) do
  tag(string, " ")
    |> tag("(")
    |> tag(".")
    |> tag("#")
end

defp tag(string, delimiter)
  [head | _] = String.split(string, delimiter)
  head
end

我想删除管道并使用某种递归函数来基于@tag_delimiter属性运行它。递归管道的正确方法是什么?

编辑DSL:

tag(string)

Feed "span(class="foo")#bar Hello my name is Dex""span Hello my name is Dex"时,我希望输出为"span"。我这样做是递归地寻找成功的第一个单词的字符。但是,我通过使用分隔符分割字符串来实现此目的。

这已经有效了,我只是想找一个更优雅的解决方案来解决我的管道问题。

2 个答案:

答案 0 :(得分:1)

您可以使用Enum.reduce功能执行此操作。

Enum.reduce(@tag_delimiters, string, fn(a, b) -> tag(b, a) end)    

答案 1 :(得分:0)

如果我了解您的需求,您可以使用String.split函数并调整模式以正确地标记输入字符串。

具体来说,您可以传递要用作模式的字符列表。实际上,您可以直接提供@tag_dividers。这是一个可能的例子:

defmodule Tags do
  @dividers [" ", "(", ".", "#"]
  def split(string) do
    List.first(String.split(string, @dividers, parts: 2))
  end
end

我使用String.split将分隔符作为列表传递。我还强制该函数只将输入分成两个标记(最多):标记和其余标记。

string = ~s{span(class="foo")#bar Hello my name is Dex}
String.split(string, [" ", "(", "."], parts: 2)
# => ["span", "class=\"foo\")#bar Hello my name is Dex"]

然后我使用List.first返回结果中的第一项。当然,我可以使用匹配[head|_]的模式并返回head,但是如果split返回一个空列表,我将不得不处理结果不匹配的情况模式。

在这种情况下,此功能只会返回nil

Tags.split(~s{span(class="foo")#bar Hello my name is Dex})
# => "span"