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

pjb*_*jb3 4 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
Run Code Online (Sandbox Code Playgroud)

blank?就像我在本示例中所做的那样,当辅助函数有用时,似乎是这种情况。似乎有药剂程序员之间的感情,这种类型的helper方法是不必要的,可以用模式匹配来完成

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

Ale*_*kin 7

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

defp blank?(str_or_nil),
  do: "" == str_or_nil |> to_string() |> String.trim()
Run Code Online (Sandbox Code Playgroud)

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


Jus*_*ood 0

Elixir 函数可以有多个函数头。有了这个,创建一个辅助函数就变得非常简单了blank?/1

defp blank?(nil), do: false
defp blank?(""), do: false
defp blank?(_), do: true
Run Code Online (Sandbox Code Playgroud)