如果没有,

问题描述

我目前正在尝试遍历Mongo的一个收藏集。为此,我正在使用此正则表达式过滤该集合。在某些情况下,正则表达式返回nil,在这种情况下它会破坏List.first,因为列表中没有内容。稍后会导致问题。

我来自Ruby,在那里我可以做next unless recipient或使用孤独的运算符List&.first到那里去。我如何才能在Elixir中做到这一点?如果接收者的值为nil,我主要想跳过当前迭代。

recipient =
  Regex.run(~r/(?<=recipient-).+\/*/,engagement["_id"])
  |> List.first()
  |> String.split("/")
  |> List.first()

解决方法

如果我对您的理解正确,则似乎您需要开始使用case块,例如:

case Regex.run(~r/(?<=recipient-).+\/*/,engagement["_id"]) do
    nil -> IO.puts "Skip List.first for Regex.run"
    out -> out |> List.first |> String.split("/") |> List.first
end

OR

Regex.run(~r/(?<=recipient-).+\/*/,engagement["_id"]) |>
case  do
    nil -> IO.puts "Skip List.first for Regex.run"
    out -> out |> List.first |> String.split("/") |> List.first
end
,

作为case语句的替代方法,您可以使用function子句的开头来匹配正则表达式的结果,即nil或match:

defmodule A do
  def go() do
    Enum.each(["a/x","c","b/x"],fn str ->
      Regex.run(~r{(a|b)/x},str,capture: :first)
      |> handle_recipient
    end)
  end

  defp handle_recipient(nil),do: :no_match  #does nothing
  defp handle_recipient([match]) do
    match
    |> String.split("/") 
    |> List.first()
    |> IO.inspect()

  end

end 

   

在iex中:

~/elixir_programs$ iex "a.ex"
Erlang/OTP 20 [erts-9.2] [source] [64-bit] [smp:4:4] [ds:4:4:10] [async-threads:10] [hipe] [kernel-poll:false]
Interactive Elixir (1.8.2) - press Ctrl+C to exit (type h() ENTER for help)

iex(1)> A.go
"a"
"b"
:ok

iex(2)> 

听起来您可能想使用Enum.reduce/3来过滤您的收藏集:

defmodule A do
  def go() do
    Enum.reduce(["a/x",[],fn str,acc ->
      Regex.run(~r{(a|b)/*},capture: :first)
      |> handle_recipient(acc)
    end)
  end

  defp handle_recipient(nil,acc),do: acc
  defp handle_recipient([match],acc) do
    result = match
             |> String.split("/")
             |> List.first
    [result|acc]
  end

end

在iex中:

~/elixir_programs$ iex "a.ex"
Erlang/OTP 20 [erts-9.2] [source] [64-bit] [smp:4:4] [ds:4:4:10] [async-threads:10] [hipe] [kernel-poll:false]
Interactive Elixir (1.8.2) - press Ctrl+C to exit (type h() ENTER for help)

iex(1)> A.go
["b","a"]

您也可以使用for来写:

defmodule A do
  def go() do
    for str <- ["a/x",reduce: [] do 
      acc -> Regex.run(~r{(a|b)/x},capture: :first)
             |> handle_recipient(acc)
    end
  end

  defp handle_recipient(nil,do: acc  
  defp handle_recipient([match],acc) do
    result = match
             |> String.split("/") 
             |> List.first()
    [result|acc]
  end

end        
,

TL; DR 使用for/1理解可过滤掉不需要的输入(不是列表的所有内容,具有二进制头)

recipient =
  for [match | _] when is_binary(match) <-
      Regex.run(~r/(?<=recipient-).+\/*/,engagement["_id"]),do: match |> String.split("/") |> List.first()

根据Regex.run/3的文档,它返回类型

nil | [binary()] | [{integer(),integer()}]

也就是说,人们可能会使用List.wrap/1nil中产生一个空列表。

recipient =
  ~r/(?<=recipient-).+\/*/
  |> Regex.run(engagement["_id"])
  |> List.wrap()
  |> List.first()
  |> String.split("/")
  |> List.first()

不幸的是,它随后会在管道上String.split/2爆炸。

也就是说,人们可能会求助于Regex.scan/3而不是{em}总是返回列表的Regex.run/3

recipient =
  ~r/(?<=recipient-).+\/*/
  |> Regex.scan(engagement["_id"])
  |> List.first()
  |> List.first() # to get to the first capture
  |> String.split("/")
  |> List.first()

但是所有这些看起来像是XY问题。你说

如果接收者的值为nil,我主要希望跳过当前迭代。

这是不可能的,但是有很多解决方法。

我会为后者投票。

recipient =
  for [match | _] when is_binary(match) <- Regex.run(~r/(?<=recipient-).+\/*/,do: match |> String.split("/") |> List.first()