如何在Elixir中对零或空白字符串进行模式匹配?

时间:2018-09-24 15:37:49

标签: elixir

这是带有测试的代码示例,其中我有一个函数来检查传入的值是否在允许的值集中,如果不是,则会引发异常,但是如果传入的值为nil或一个空白字符串,它只返回false。这里的想法是,任何一种空白值都意味着没有价值。如果存在与有效值之一不匹配的非空白值,那么我们确实要引发异常,因为该值无效。还要想象这个值来自命令行参数或Phoenix请求参数,在这里我们不能将输入值控制为nil,我们必须检查一个空值,nil,一个空字符串或仅包含一个字符串的所有排列。空格。

ExUnit.start()

defmodule ValidColor do
  @valid_colors MapSet.new(~w[red green blue])

  def valid?(color) do
    cond do
      blank?(color) -> false
      MapSet.member?(@valid_colors, color) -> true
      true -> raise "invalid color"
    end
  end

  defp blank?(value) do
    case value do
      nil -> true
      v when is_binary(v) -> v =~ ~r/\A\s*\z/
      _ -> false
    end
  end
end

defmodule ValidColorTest do
  use ExUnit.Case, async: true

  test "nil" do
    refute ValidColor.valid?(nil)
  end

  test "empty string" do
    refute ValidColor.valid?("")
  end

  test "string with only blank characters" do
    refute ValidColor.valid?("     ")
  end

  test "invalid color" do
    assert_raise RuntimeError, "invalid color", fn ->
      ValidColor.valid?("yellow")
    end
  end

  test "valid color" do
    assert ValidColor.valid?("red")
  end
end

就像我在本示例中所做的那样,当blank?辅助函数有用时,似乎是这种情况。似乎有a sentiment among Elixir programmers that this type of helper method is unnecessary and can be done with pattern matching

如何仅通过模式匹配而不是blank?帮助函数来实现这样的功能?

4 个答案:

答案 0 :(得分:4)

尽管此处给出的所有答案在某种程度上都是正确的,但它们在语义上并不是完美的。您实际上想要的是将nil视为一个空字符串并拒绝它。做到简单:

defp blank?(str_or_nil),
  do: "" == str_or_nil |> to_string() |> String.trim()

请注意,该解决方案与到目前为止提供的其他解决方案不同,它适用于 all 空格(在UTF-8规范中定义为空格)。

答案 1 :(得分:3)

Change flatMap to compactMap 情况很简单:

nil

要检查字符串是否仅包含空格字符,需要更多涉及的模式匹配:

defp blank?(nil), do: true

答案 2 :(得分:2)

您也可以使用case/2

def blank?(str) do
  case str do
    nil -> true
    "" -> true
    " " <> r -> blank?(r)
    _ -> false 
  end
end

注意:在这种情况下,我们只考虑空格,必须像@@@@@@@@@@@@@@@@@ bertbert在其答案中所做的那样,考虑“ \ n”,“ \ r”和“ \ t”上的模式匹配。

答案 3 :(得分:0)

Elixir功能可以具有多个功能头。这样,创建一个blank?/1辅助函数就很简单了。

defp blank?(nil), do: false
defp blank?(""), do: false
defp blank?(_), do: true