web-dev-qa-db-fra.com

Expressions régulières dans le boîtier Elixir

Pouvez-vous utiliser une expression régulière dans un case dans Elixir?

Donc quelque chose dans le sens de ceci:

case some_string do
  "string"        -> # do something
  ~r/string[\d]+/ -> # do something
  _               -> # do something
end
33
Daisuke Shimamoto

Avec case ce n'est pas possible, mais vous pouvez utiliser cond:

cond do
  some_string == "string"                     -> # do something
  String.match?(some_string, ~r/string[\d]+/) -> # do something
  true                                        -> # do something
end

La raison en est qu'il n'y a aucun moyen de se connecter à la correspondance de modèle en appelant des fonctions spéciales pour des valeurs spécifiques. Je suppose que vous avez eu l'idée de Ruby, qui implémente cela en définissant l'opérateur spécial ===. Cela sera implicitement appelé par la déclaration de cas de Ruby et pour une expression régulière, elle correspondra à la valeur donnée.

37
Patrick Oscity

Comme Patrick l'a dit dans sa réponse, il n'y a rien de intégré pour cela, et cond est probablement votre meilleure option.

Mais pour ajouter une autre option et montrer la flexibilité d'Elixir: étant donné que case n'est qu'une macro dans Elixir, vous pouvez implémenter votre propre macro comme regex_case pour faire ça.

Vous devez garder à l'esprit que cela pourrait rendre le code plus difficile à comprendre pour les nouvelles personnes sur le projet, mais si vous faites beaucoup de correspondance d'expressions régulières, le compromis pourrait peut-être avoir un sens. Sois le juge.

J'ai implémenté cela il y a quelque temps, juste pour voir que c'était possible:

defmodule RegexCase do
  defmacro regex_case(string, do: lines) do
    new_lines = Enum.map lines, fn ({:->, context, [[regex], result]}) ->
      condition = quote do: String.match?(unquote(string), unquote(regex))
      {:->, context, [[condition], result]}
    end

    # Base case if nothing matches; "cond" complains otherwise.
    base_case = quote do: (true -> nil)
    new_lines = new_lines ++ base_case

    quote do
      cond do
        unquote(new_lines)
      end
    end
  end
end

defmodule Run do
  import RegexCase

  def run do
    regex_case "hello" do
      ~r/x/ -> IO.puts("matches x")
      ~r/e/ -> IO.puts("matches e")
      ~r/y/ -> IO.puts("matches y")
    end
  end
end

Run.run
25
Henrik N