7

テキストの解析を行う Erlang プログラムを作成していると、正規表現を使用してパターン マッチを実行したい状況によく遭遇します。

たとえば、次のようなことができたらいいのにと思います。ここで、 ~ は「作成された」正規表現一致演算子です。

my_function(String ~ ["^[A-Za-z]+[A-Za-z0-9]*$"]) ->
    ....

正規表現モジュール (re) については知っていますが、パターン マッチング時やガード中に関数を呼び出すことはできません。

また、大文字と小文字を区別しない方法で文字列の照合を行うことができればと思います。これは便利です。たとえば、HTTP ヘッダーを解析するときに、「Str ~ {Pattern, Options}」が「オプション オプションを使用してパターン パターンに対して Str を一致させる」ことを意味する次のようなことをしたいと思います。

handle_accept_language_header(Header ~ {"Accept-Language", [case_insensitive]}) ->
    ...

2 つの質問:

  1. 通常、標準の Erlang だけを使用してこれをどのように処理しますか? 簡潔さと読みやすさの点で、これに近いメカニズム/コーディングスタイルはありますか?

  2. Erlang でこれに対処するための作業 (EEP?) はありますか?

4

6 に答える 6

7

事前に正規表現を実行してから、結果に対してパターン マッチを実行する以外に、選択肢はほとんどありません。これは、あなたが求めているものに近づく非常に単純な例ですが、正規表現を2回繰り返す必要があるという欠陥があります。マクロを使用して各正規表現を 1 か所で定義することで、この問題を軽減できます。

-module(multire).

-compile(export_all).

multire([],_) ->
    nomatch;
multire([RE|RegExps],String) ->
    case re:run(String,RE,[{capture,none}]) of
    match ->
        RE;
    nomatch ->
        multire(RegExps,String)
    end.


test(Foo) ->
    test2(multire(["^Hello","world$","^....$"],Foo),Foo).

test2("^Hello",Foo) ->
    io:format("~p matched the hello pattern~n",[Foo]);
test2("world$",Foo) ->
    io:format("~p matched the world pattern~n",[Foo]);
test2("^....$",Foo) ->
    io:format("~p matched the four chars pattern~n",[Foo]);
test2(nomatch,Foo) ->
    io:format("~p failed to match~n",[Foo]).
于 2009-11-02T15:35:47.150 に答える
6

可能性としては、Erlang Web スタイルの注釈 (マクロ) をre Erlang モジュールと組み合わせて使用​​することができます。例は、これを説明するためのおそらく最良の方法です。

最終的なコードは次のようになります。

[...]
?MATCH({Regexp, Options}).
foo(_Args) ->
  ok.
[...]

MATCHマクロは、foo関数の直前に実行されます。正規表現パターンが一致しない場合、実行フローは失敗します。

match 関数は次のように宣言されます。

?BEFORE.
match({Regexp, Options}, TgtMod, TgtFun, TgtFunArgs) ->
String = proplists:get_value(string, TgtArgs),
case re:run(String, Regexp, Options) of
  nomatch ->
    {error, {TgtMod, match_error, []}};
  {match, _Captured} ->
    {proceed, TgtFunArgs}
end.

その点に注意してください:

  • BEFOREは、マクロがターゲット関数の前に実行されることを示します (AFTER マクロも利用可能です)。
  • match_error は、モジュールで指定されたエラー ハンドラーであり、一致に失敗した場合に実行するコードが含まれています (何もない可能性があり、実行フローをブロックするだけです)。
  • このアプローチには、正規表現の構文とオプションをreモジュールと統一するという利点があります (混乱を避けるため)。

Erlang Web アノテーションの詳細については、こちらをご覧ください。

http://wiki.erlang-web.org/Annotations

そしてここ:

http://wiki.erlang-web.org/HowTo/CreateAnnotation

このソフトウェアはオープン ソースであるため、注釈エンジンを再利用することをお勧めします。

于 2009-11-02T16:16:54.710 に答える
3

re モジュールを使用できます。

re:run(String, "^[A-Za-z]+[A-Za-z0-9]*$").
re:run(String, "^[A-Za-z]+[A-Za-z0-9]*$", [caseless]).

編集:

match(String, Regexps) -> 
  case lists:dropwhile(
               fun({Regexp, Opts}) -> re:run(String, Regexp, Opts) =:= nomatch;
                  (Regexp) -> re:run(String, Regexp) =:= nomatch end,
               Regexps) of
    [R|_] -> R;
    _     -> nomatch
  end.

example(String) ->
  Regexps = ["$RE1^", {"$RE2^", [caseless]}, "$RE3"]
  case match(String, Regexps) of
    nomatch -> handle_error();
    Regexp -> handle_regexp(String, Regexp)
    ...
于 2009-11-02T11:29:47.473 に答える
3
  1. 文字列については、「re」モジュールを使用できます。その後、結果セットを反復処理します。私の知る限り、それを行う別の方法はないのではないかと心配しています。それが正規表現がある理由です。

  2. HTTP ヘッダーの場合、多くの可能性があるため、(潜在的に) 非常に長い式を記述するよりも、結果セットを反復処理する方が適切なオプションであると考えています。

  3. EEP 仕事 : わかりません。

于 2009-11-02T11:35:00.880 に答える
2
  1. Erlangはパターンの正規表現を処理しません。
  2. いいえ。
于 2009-11-05T00:22:56.180 に答える
1

申し訳ありませんが、正規表現ではパターン マッチを実行できません。だからあなたはしなければならない

my_function(String) -> Matches = re:run(String, "^[A-Za-z]+[A-Za-z0-9]*$"),
                       ...
于 2009-11-02T14:01:20.450 に答える