2010-10-31 16 views
33

Usando Parsec 3.1, es posible analizar varios tipos de entradas:Parsec con data.text

  • [Char] con Text.Parsec.String
  • Data.ByteString con Text.Parsec.ByteString
  • Data.ByteString.Lazy con Text.Parsec.ByteString.Lazy

I no veo nada para el módulo Data.Text. Quiero analizar el contenido de Unicode sin sufrir las ineficiencias String. Por lo tanto, hemos creado 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 
  1. ¿Tiene sentido hacerlo?
  2. ¿Es esto compatible con el resto de API de Parsec?

Comentarios adicionales:

he tenido que añadir {-# LANGUAGE NoMonomorphismRestriction #-} pragma en mis módulos de análisis sintáctico para hacer que funcione.

El análisis Text es una cosa, la construcción de un AST con Text es otra cosa. También necesitaré a mi packString antes del regreso:

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 

Respuesta

9

que se parece exactamente lo que tiene que hacer.

Debe ser compatible con el resto de Parsec, incluye 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.

+0

Está funcionando bien excepto por los módulos 'Text.Parsec.Language' y' Text.Parsec.Token' que están restringidos a 'String'. Puedo solucionar ese problema ejecutando mi propia tokenización. 'Text.Parsec.Language' es solo un gadget de todos modos (¿Mondrian? ¿Alguien?). – gawi

+0

¡Ah! Me pregunto si podemos generalizar esos a cualquier secuencia de Char de una manera compatible hacia atrás. No parece difícil, pero como nunca uso esos módulos, no tengo ningún buen caso de prueba. –

5

Agregué una función parseFromUtf8File para ayudar a leer los archivos codificados UTF-8 de manera eficiente. Funciona sin problemas con los personajes umlaut. El tipo de función coincide con parseFromFile desde Text.Parsec.ByteString. Esta versión usa ByteStrings estrictos.

-- 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 [email protected] runs a strict bytestring parser 
-- @[email protected] on the input read from @[email protected] using 
-- 'ByteString.readFile'. Returns either a 'ParseError' ('Left') or a 
-- value of type @[email protected] ('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) 
Cuestiones relacionadas