En utilisant parsec avec data.text
Question
En utilisant Parsec 3.1
, il est possible d'analyser plusieurs types d'entrées:
-
[Char]
avecText.Parsec.String
-
Data.ByteString
avecText.Parsec.ByteString
-
Data.ByteString.Lazy
avecText.Parsec.ByteString.Lazy
Je ne vois pas quoi que ce soit pour le module Data.Text
. Je veux analyser le contenu Unicode sans souffrir de l'inefficacité de String
. J'ai donc créé le module suivant sur la base du module Text.Parsec.ByteString
:
{-# LANGUAGE FlexibleInstances, MultiParamTypeClasses #-}
{-# OPTIONS_GHC -fno-warn-orphans #-}
module Text.Parsec.Text
( Parser, GenParser
) where
import Text.Parsec.Prim
import qualified Data.Text as T
instance (Monad m) => Stream T.Text m Char where
uncons = return . T.uncons
type Parser = Parsec T.Text ()
type GenParser t st = Parsec T.Text st
- Est-il logique de le faire?
- ce compatible avec le reste de l'API parsec?
Autres commentaires:
Je devais ajouter dans mes {-# LANGUAGE NoMonomorphismRestriction #-}
pragma modules parse pour le faire fonctionner.
Parsing Text
est une chose, la construction d'un AST avec Text
est une autre chose. Je vais aussi devoir pack
mon String
avant le retour:
module TestText where
import Data.Text as T
import Text.Parsec
import Text.Parsec.Prim
import Text.Parsec.Text
input = T.pack "xxxxxxxxxxxxxxyyyyxxxxxxxxxp"
parser = do
x1 <- many1 (char 'x')
y <- many1 (char 'y')
x2 <- many1 (char 'x')
return (T.pack x1, T.pack y, T.pack x2)
test = runParser parser () "test" input
La solution
qui ressemble exactement ce que vous devez faire.
Il doit être compatible avec le reste de parsecs, inclure les parseurs Parsec.Char.
Si vous utilisez Cabal pour construire votre programme, s'il vous plaît mettre une limite supérieure de parsec-3.1 dans votre description de l'emballage, au cas où le mainteneur décide d'inclure cette instance dans une version future de parsecs.
Autres conseils
Depuis parsec 3.1.2 soutien de data.text est intégré! Voir http://hackage.haskell.org/package/parsec-3.1.2
Si vous êtes coincé avec une version plus ancienne, les extraits de code dans d'autres réponses sont utiles aussi.
J'ai ajouté une parseFromUtf8File
fonction de lecture aide UTF-8 fichiers codés de façon efficace. Fonctionne parfaitement avec les caractères tréma. matchs de type Fonction parseFromFile
de Text.Parsec.ByteString
. Cette version utilise des chaînes ordinaires strictes.
-- A derivate work from
-- http://stackoverflow.com/questions/4064532/using-parsec-with-data-text
{-# LANGUAGE FlexibleInstances, MultiParamTypeClasses #-}
{-# OPTIONS_GHC -fno-warn-orphans #-}
module Text.Parsec.Text
( Parser, GenParser, parseFromUtf8File
) where
import Text.Parsec.Prim
import qualified Data.Text as T
import qualified Data.ByteString as B
import Data.Text.Encoding
import Text.Parsec.Error
instance (Monad m) => Stream T.Text m Char where
uncons = return . T.uncons
type Parser = Parsec T.Text ()
type GenParser t st = Parsec T.Text st
-- | @parseFromUtf8File p filePath@ runs a strict bytestring parser
-- @p@ on the input read from @filePath@ using
-- 'ByteString.readFile'. Returns either a 'ParseError' ('Left') or a
-- value of type @a@ ('Right').
--
-- > main = do{ result <- parseFromFile numbers "digits.txt"
-- > ; case result of
-- > Left err -> print err
-- > Right xs -> print (sum xs)
-- > }
parseFromUtf8File :: Parser a -> String -> IO (Either ParseError a)
parseFromUtf8File p fname = do
raw <- B.readFile fname
let input = decodeUtf8 raw
return (runP p () fname input)