2009-06-17 11 views
6

Jaki jest najlepszy sposób na wykorzystanie wyrażeń regularnych z opcjami (flag) w Haskellwyrażenia regularne case-niewrażliwy

używam

Text.Regex.PCRE 

Dokumentacja wymienia kilka ciekawych opcji, takich jak compCaseless, compUTF8 .. Ale nie wiem jak ich używać z (= ~)

Odpowiedz

16

Wszystkie moduły Text.Regex.* ogromnym stopniu korzystają z typeclasses, które są tam dla rozciągliwości i "przeciążania" -jakiego zachowania, ale sprawiają, że używanie mniej obvio nas od samego patrzenia na typy.

Najprawdopodobniej zostałeś już uruchomiony z podstawowego matchera =~.

(=~) :: 
    (RegexMaker Regex CompOption ExecOption source 
    , RegexContext Regex source1 target) 
    => source1 -> source -> target 
(=~~) :: 
    (RegexMaker Regex CompOption ExecOption source 
    , RegexContext Regex source1 target, Monad m) 
    => source1 -> source -> m target 

Aby korzystać =~, musi istnieć wystąpienie RegexMaker ... dla LHS i RegexContext ... dla RHS i wynik.

class RegexOptions regex compOpt execOpt | ... 
     | regex -> compOpt execOpt 
     , compOpt -> regex execOpt 
     , execOpt -> regex compOpt 
class RegexOptions regex compOpt execOpt 
     => RegexMaker regex compOpt execOpt source 
     | regex -> compOpt execOpt 
     , compOpt -> regex execOpt 
     , execOpt -> regex compOpt 
    where 
    makeRegex :: source -> regex 
    makeRegexOpts :: compOpt -> execOpt -> source -> regex 

Ważny wystąpienie wszystkich tych klas (na przykład, regex=Regex, compOpt=CompOption, execOpt=ExecOption, a source=String) oznacza, że ​​jest możliwe, aby skompilować regex z compOpt,execOpt opcje z jakiejś formy source. (Ponadto, biorąc pod uwagę niektóre regex typ, istnieje dokładnie jedna compOpt,execOpt zestaw, który idzie wraz z nim. Wiele różnych source typów są w porządku, choć.)

class Extract source 
class Extract source 
     => RegexLike regex source 
class RegexLike regex source 
     => RegexContext regex source target 
    where 
    match :: regex -> source -> target 
    matchM :: Monad m => regex -> source -> m target 

Ważny wystąpienie wszystkich tych klas (np regex=Regex , source=String, target=Bool) oznacza, że ​​można dopasować source i regex, aby uzyskać target. (Inne ważne target s podane są specyficzne regex i sourceInt, MatchResult String, MatchArray itp)

umieścić je razem i to jest dość oczywiste, że =~ i =~~ są po prostu funkcje convenience

source1 =~ source 
    = match (makeRegex source) source1 
source1 =~~ source 
    = matchM (makeRegex source) source1 

a także, że =~ i =~~ nie pozostawiają miejsca na przesłanie różnych opcji do makeRegexOpts.

Można tworzyć własne

(=~+) :: 
    (RegexMaker regex compOpt execOpt source 
    , RegexContext regex source1 target) 
    => source1 -> (source, compOpt, execOpt) -> target 
source1 =~+ (source, compOpt, execOpt) 
    = match (makeRegexOpts compOpt execOpt source) source1 
(=~~+) :: 
    (RegexMaker regex compOpt execOpt source 
    , RegexContext regex source1 target, Monad m) 
    => source1 -> (source, compOpt, execOpt) -> m target 
source1 =~~+ (source, compOpt, execOpt) 
    = matchM (makeRegexOpts compOpt execOpt source) source1 

które mogą być używane jak

"string" =~+ ("regex", CompCaseless + compUTF8, execBlank) :: Bool 

lub nadpisać =~ i =~~ z metod, która może przyjąć opcje

import Text.Regex.PCRE hiding ((=~), (=~~)) 

class RegexSourceLike regex source 
    where 
    makeRegexWith source :: source -> regex 
instance RegexMaker regex compOpt execOpt source 
     => RegexSourceLike regex source 
    where 
    makeRegexWith = makeRegex 
instance RegexMaker regex compOpt execOpt source 
     => RegexSourceLike regex (source, compOpt, execOpt) 
    where 
    makeRegexWith (source, compOpt, execOpt) 
     = makeRegexOpts compOpt execOpt source 

source1 =~ source 
    = match (makeRegexWith source) source1 
source1 =~~ source 
    = matchM (makeRegexWith source) source1 

lub może po prostu użyj match, makeRegexOpts itp. Bezpośrednio tam, gdzie jest to konieczne.

+0

Ach, wygląda na to, że zostałem pokonany. To właśnie dostaję za pisanie wszelkiego rodzaju niepotrzebnych rzeczy: -/ – ephemient

+0

Ah, teraz czuję się trochę winny, twój na pewno oferuje o wiele bardziej wszechstronny przegląd! Lubię twoją sugestię dla (= ~ +) przy okazji. – dukedave

+0

to naprawdę pełna i wyczerpująca odpowiedź, chciałbym nagrodzić wysiłek, ale nie wiem, czy powszechną praktyką jest zmiana "zaakceptowanej odpowiedzi"? tak czy inaczej, jestem nowy dla Haskella, a ta odpowiedź naprawdę pomogła mi zrozumieć pewne sprytne zasady tego języka (także, mała literówka na początku, którą napisałeś = ~ zamiast = ~~) –

7

Nie wiem nic o Haskell, ale jeśli używasz biblioteki regex opartej na PCRE, możesz użyć modyfikatorów trybu wewnątrz wyrażenia regularnego. Aby dopasować „bezłuskową” w przypadku, niewrażliwego mody, można użyć tego wyrażenia regularnego w PCRE: (? I)

(?i)caseless 

Modyfikator zastępuje dowolny tryb czułości przypadek albo przypadek opcję nieczułości, który został ustawiony na zewnątrz wyrażenia regularnego. Działa również z operatorami, które nie pozwalają na ustawienie żadnych opcji.

Podobnie (? S) włącza "tryb pojedynczego wiersza", który sprawia, że ​​kropka pasuje do podziałów linii, (? M) włącza "tryb wielowierszowy", który powoduje, że^i $ dopasowują się do linii podziału i (? X) włącza tryb swobodnego odstępu (puste przestrzenie i przerwy w linii poza klasami znaków są nieistotne). Możesz łączyć litery. (? ismx) włącza wszystko. Łącznik wyłącza opcje. (? -i) powoduje, że wielkość regex jest wrażliwa. (? x-i) rozpoczyna regex z rozróżnianiem dużych i małych liter.

+0

to też działa! jest o wiele prostsze, ale również mniej ogólne niż przyjęte rozwiązanie. –

+0

+1 Pozwala nam to na zachowanie idomatic operatora '= ~' i wyrażenie regex zdefiniowane jako 'String'. O wiele bardziej podstawowy! –

Powiązane problemy