2009-11-02 11 views
7

當我編寫用於文本解析的Erlang程序時,我經常遇到使用正則表達式進行模式匹配的情況。如何使用正則表達式來執行Erlang模式匹配?

例如,我希望我可以做這樣的事情,在那裏〜是一個「由」正則表達式匹配操作:

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

我知道的正則表達式模塊(重),但據我所知,你不能在模式匹配或警衛時調用函數。

另外,我希望匹配的字符串可以以不區分大小寫的方式完成。這很方便,例如,解析HTTP頭時,我很樂意做這樣的事情,其中​​「海峽〜{模式,選項}」,「使用選項選項阻止圖形模式匹配海峽」的意思是:

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

兩個問題:

  1. 你如何使用標準的Erlang來處理這個問題?在簡潔性和易讀性方面,是否有一些機制/編碼風格與此接近?

  2. 是否有任何工作(EEP?)在Erlang進行解決?

+0

我懷疑一個EEP添加正則表達式,因爲模式將被支持。所有當前模式都可以在恆定時間內評估,正則表達式不能。 (長度/ 1或許是唯一例外的常量時間規則) – archaelus 2009-11-03 12:47:36

回答

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) 
    ... 
+1

是的,re模塊在正則表達式上做得很好,但是您AFAIK在模式匹配或守衛中不能調用函數。 – 2009-11-02 11:42:20

+1

如果我只通過模式匹配來理解你的意思...... Erlang應該爲你制定一個匹配字符串的正則表達式,或者是什麼? – Zed 2009-11-02 12:48:38

+0

我認爲他想要的是類似is_match(RegExp,S)bif用於警衛,所以: foo(X)when is_match(RE1,X) - > one_thing(); foo(X)當is_match(RE2,X) - > another_thing()。 等 – 2009-11-03 12:38:46

3
  1. 對於字符串,你可以使用 '重' 模塊:之後,你遍歷結果集。恐怕沒有其他辦法可以做到了。AFAIK:這就是爲什麼有正則表達式的原因。

  2. 對於HTTP標頭,由於可能有很多,所以我會考慮迭代結果集,以更好地選擇而不是(可能)編寫很長的表達式。

  3. EEP工作:我不知道。

+1

無理由地指定「反對票」是非生產性的。 – jldupont 2009-11-02 13:15:41

+0

你並不孤單:) – 2012-06-07 18:26:54

1

無法在正則表達式上模式匹配,抱歉。所以你必須做

my_function(String) -> Matches = re:run(String, "^[A-Za-z]+[A-Za-z0-9]*$"), 
         ... 
6

你真的沒有太多的選擇,比預先運行你的正則表達式,然後模式匹配的結果。這裏有一個非常簡單的例子,它接近我認爲你所追求的東西,但它確實遭受了你需要重複兩次正則表達式的缺陷。您可以通過使用宏在一個地方定義每個正則表達式來減輕痛苦。

-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]). 
6

一種可能性可以是使用二郎Web樣式註釋(宏)與重新二郎模塊相結合。一個例子可能是說明這一點的最好方法。

這是你的最終代碼將如何看起來像:

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

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說,宏將你的目標函數之前之後的宏也可被執行( )。
  • 的match_error是你的錯誤處理程序,您的模塊中指定,幷包含你想,如果你不匹配執行(也許沒什麼,只是阻止執行流程中)
  • 這種方法保持正則表達式的優勢碼語法和選項與re模塊一致(避免混淆)。對這裏的Erlang的Web註解

的更多信息:

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

這裏:

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

該軟件是開源的,所以你可能想重用他們的註釋引擎。

2
  1. Erlang不處理模式中的正則表達式。