Comment énoncez-vous un modèle regex dans Haskell?

Nov 28 2020

J'essaye de faire une regex remplacer par le code suivant

import Text.RE.Replace
import Text.RE.TDFA.String

onlyLetters :: String -> String
onlyLetters s = replaceAll "" $ s *=~ [re|$([^a-zA-Z])|]

J'ai trouvé très difficile de trouver une documentation compréhensible à ce sujet. Cela produit l'erreur de compilation:

    src\Pangram.hs:6:53: error: parse error on input `]'
  |
6 | onlyLetters s = replaceAll "" $ (s *=~ [re|[a-zA-Z]|]) | ^ Progress 1/2 -- While building package pangram-2.0.0.12 (scroll up to its section to see the error) using: C:\sr\setup-exe-cache\x86_64-windows\Cabal-simple_Z6RU0evB_3.0.1.0_ghc-8.8.4.exe --builddir=.stack-work\dist\29cc6475 build lib:pangram test:test --ghc-options " -fdiagnostics-color=always" Process exited with code: ExitFailure 1 PS C:\Users\mcleg\Exercism\haskell\pangram> stack test pangram> configure (lib + test) Configuring pangram-2.0.0.12... pangram> build (lib + test) Preprocessing library for pangram-2.0.0.12.. Building library for pangram-2.0.0.12.. [1 of 2] Compiling Pangram src\Pangram.hs:7:56: error: parse error on input `]' | 7 | onlyLetters s = replaceAll "" $ s *=~ [re|$([^a-zA-Z])|]
  |                                                        ^

Progress 1/2

--  While building package pangram-2.0.0.12 (scroll up to its section to see the error) using:
      C:\sr\setup-exe-cache\x86_64-windows\Cabal-simple_Z6RU0evB_3.0.1.0_ghc-8.8.4.exe --builddir=.stack-work\dist\29cc6475 build lib:pangram test:test --ghc-options " -fdiagnostics-color=always"
    Process exited with code: ExitFailure 1

Quel est le problème avec ce support et comment puis-je le faire correctement? Merci -Skye

Réponses

3 WillemVanOnsem Nov 28 2020 at 18:56

La syntaxe[…|…|] est quasi-citation [haskell-wiki] . Il s'agit d'une extension de la syntaxe de Haskell et non activée par défaut.

Vous pouvez l'activer avec un LANGUAGEpragma:

{-# LANGUAGE QuasiQuotes #-}

import Text.RE.Replace
import Text.RE.TDFA.String

onlyLetters :: String -> String
onlyLetters s = replaceAll "" $ s *=~ [re|$([^a-zA-Z])|]

Les quasiquotes généreront du code Haskell et celui-ci sera ensuite utilisé dans le programme Haskell. Cela signifie qu'à travers les quasiquotes, la validation de l'expression régulière peut être effectuée au moment de la compilation et pourrait même légèrement optimiser l'efficacité par rapport à la compilation de l'expression régulière au moment de l'exécution.

Pour la onlyLettersfonction donnée , on obtient alors:

*Main> onlyLetters "fo0b4r"
"fobr"
2 JamesBrock Nov 29 2020 at 21:02

La réponse de Willem Van Onsem est une meilleure réponse à la question, mais je vais suggérer une réponse «essayez ceci à la place» .

C'est ainsi que vous pouvez effectuer un remplacement de texte en Haskell simple sans la complication des expressions régulières quasi-citées.

Avec https://hackage.haskell.org/package/replace-megaparsec/docs/Replace-Megaparsec.html#v:streamEdit

{-# LANGUAGE TypeFamilies #-}

import Text.Megaparsec
import Text.Megaparsec.Char
import Replace.Megaparsec
import Data.Void

-- | Invert a single-token parser “character class”.
-- | For example, match any single token except a letter or whitespace: `anySingleExcept (letterChar <|> spaceChar)`
anySingleExcept :: (MonadParsec e s m, Token s ~ Char) => m (Token s) -> m (Token s)
anySingleExcept p = notFollowedBy p *> anySingle

-- | A parser monad pattern which matches anything except letters.
nonLetters :: Parsec Void String String
nonLetters = many (anySingleExcept letterChar) 

onlyLetters :: String -> String
onlyLetters = streamEdit nonLetters (const "")

onlyLetters "fo0b4r"
"fobr"