2009-06-17 27 views

Respuesta

16

Todos los módulos Text.Regex.* hacen un uso intensivo de clases de tipos, que son existe un comportamiento de extensibilidad y "sobrecarga", pero hace que el uso sea menos obvio nosotros de solo ver tipos.

Ahora, es probable que haya comenzado desde el comparador básico =~.

(=~) :: 
    (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 

Para utilizar =~, debe existir una instancia de RegexMaker ... para la LHS, y RegexContext ... para el RHS y resultado.

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 

una instancia válida de todas estas clases (por ejemplo, regex=Regex, compOpt=CompOption, execOpt=ExecOption, y source=String) significa que es posible compilar un regex con compOpt,execOpt Opciones de algún tipo source. (También, dado alguna regex tipo, hay exactamente un compOpt,execOpt conjunto que va junto con él. Un montón de diferentes source tipos están bien, sin embargo.)

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 

una instancia válida de todas estas clases (por ejemplo, regex=Regex , source=String, target=Bool) significa que es posible hacer coincidir un source y un regex para obtener un target. (Otros válidos target s Dadas estas específica regex y source son Int, MatchResult String, MatchArray, etc.)

poner estos juntos y que es bastante obvio que =~ y =~~ son simplemente funciones de confort

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

y también que =~ y =~~ no dejan espacio para pasar varias opciones al makeRegexOpts.

Se podría hacer su propia

(=~+) :: 
    (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 

que podría ser utilizado como

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

o sobrescribir =~ y =~~ con métodos que puede aceptar opciones

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 

o usted podría use match, makeRegexOpts, etc. directamente donde sea necesario.

+0

Ah, parece que he sido golpeado por la solución. Eso es lo que obtengo por escribir todo tipo de cosas innecesarias: -/ – ephemient

+0

¡Ah, ahora me siento un poco culpable, sin dudas el suyo ofrece una visión general mucho más completa! Me gusta tu sugerencia para (= ~ +) por cierto. – dukedave

+0

es una respuesta muy completa y completa. Me gustaría recompensar el esfuerzo, pero no sé si es una práctica común cambiar la "respuesta aceptada". de todos modos, soy nuevo en Haskell, y esta respuesta realmente me ayudó a entender algunos principios ingeniosos del lenguaje (también, pequeño error al escribir que escribió = ~ en lugar de = ~~) –

7

No sé nada de Haskell, pero si usa una biblioteca de expresiones regulares basada en PCRE, puede usar modificadores de modo dentro de la expresión regular. Para hacer coincidir "sin vaina" de una manera insensible caso, se puede utilizar esta expresión regular en PCRE: (? I)

(?i)caseless 

El modificador modo anula cualquier opción de insensibilidad mayúsculas y minúsculas o un caso que fue puesto fuera de la expresión regular. También funciona con operadores que no le permiten establecer ninguna opción.

Del mismo modo, (?) Enciende el "modo de línea única" que hace que la línea coincida con los puntos, (? M) activa el "modo multilínea" que hace^y $ coincidir en saltos de línea, y (?) activa el modo de espacio libre (los espacios sin escalas y los saltos de línea fuera de las clases de caracteres son insignificantes). Puedes combinar las letras. (? ismx) enciende todo. Un guión desactiva las opciones. (? -i) hace que la expresión regular sea sensible. (? x-i) inicia una expresión regular sensible a mayúsculas y minúsculas.

+0

¡también funciona! es mucho más simple pero también menos genérico que la solución aceptada –

+0

+1 Esto nos permite mantener el operador idomatic '= ~' y hacer que la expresión regular se defina como 'String'. ¡Mucho más básico! –

Cuestiones relacionadas