haskell - Usando Parsec con Data.Text
(3)
Usando Parsec 3.1
, es posible analizar varios tipos de entradas:
-
[Char]
conText.Parsec.String
-
Data.ByteString
conText.Parsec.ByteString
-
Data.ByteString.Lazy
conText.Parsec.ByteString.Lazy
No veo nada para el módulo Data.Text
. Quiero analizar el contenido de Unicode sin sufrir las ineficiencias de String
. Así que creé el siguiente módulo basado en el módulo 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
- ¿Tiene sentido hacerlo?
- ¿Es esto compatible con el resto de la API de Parsec?
Comentarios adicionales:
Tuve que agregar {-# LANGUAGE NoMonomorphismRestriction #-}
pragma en mis módulos de análisis para que funcione.
El análisis de Text
es una cosa, construir un AST con Text
es otra cosa. También necesitaré pack
mi String
antes de regresar:
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
¡Ya que el soporte de Parsec 3.1.2 de Data.Text está incorporado! Ver http://hackage.haskell.org/package/parsec-3.1.2
Si está atascado con una versión anterior, los fragmentos de código en otras respuestas también son útiles.
Eso parece exactamente lo que necesitas hacer.
Debería ser compatible con el resto de Parsec, incluir los analizadores Parsec.Char.
Si está utilizando Cabal para construir su programa, por favor ponga un límite superior de parsec-3.1 en la descripción de su paquete, en caso de que el mantenedor decida incluir esa instancia en una versión futura de Parsec.
parseFromUtf8File
una función parseFromUtf8File
para ayudar a leer los archivos codificados UTF-8 de manera eficiente. Funciona sin problemas con los personajes umlaut. Tipo de función coincide con parseFromFile
de Text.Parsec.ByteString
. Esta versión usa ByteStrings estrictos.
-- A derivate work from
-- http://.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)