2010-10-31 70 views
33

使用Parsec 3.1,可以解析几种类型的输入:使用秒差距与Data.Text

  • [Char]Text.Parsec.String
  • Data.ByteStringText.Parsec.ByteString
  • Data.ByteString.LazyText.Parsec.ByteString.Lazy

我没有看到Data.Text模块的任何内容。我想解析Unicode内容而不会受到效率低下的影响。所以我创建基于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. 是否有意义这样做呢?
  2. 它与Parsec API的其余部分兼容吗?

附加注释:

我不得不添加{-# LANGUAGE NoMonomorphismRestriction #-}编译在我的解析模块,使其工作。

解析Text是一回事,建立一个AST与Text是另一回事。我还需要回归前packString

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 

回答

9

这看起来像你需要做什么。

它应该与Parsec的其余部分兼容,包括Parsec.Char解析器。

如果您使用Cabal构建您的程序,请在您的软件包描述中放置parsec-3.1的上限,以防维护人员决定将该实例包含在未来版本的Parsec中。

+0

除了限制为String的'Text.Parsec.Language'和'Text.Parsec.Token'模块,它工作正常。我可以通过执行我自己的标记来解决这个问题。无论如何,“Text.Parsec.Language”只是一个小工具(蒙德里安?任何人?)。 – gawi 2010-11-02 01:17:41

+0

啊!我想知道我们是否能以向后兼容的方式推广到任何字符流。它看起来不难,但因为我从来没有使用这些模块,所以我没有任何好的测试用例。 – 2010-11-04 16:04:42

5

我添加了一个函数parseFromUtf8File来帮助以有效的方式读取UTF-8编码文件。完美搭配变音符号。功能类型匹配parseFromFileText.Parsec.ByteString。该版本使用严格的ByteStrings。

-- 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)