使用Parsec 3.1
,可以解析几种类型的输入:
[Char]
与Text.Parsec.String
Data.ByteString
与Text.Parsec.ByteString
Data.ByteString.Lazy
与Text.Parsec.ByteString.Lazy
我没有看到Data.Text
模块的任何内容。我想解析Unicode内容而不会受到String
低效率的影响。所以我基于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
补充意见:
我必须在我的解析模块中添加{-# LANGUAGE NoMonomorphismRestriction #-}
pragma才能使其正常工作。
解析Text
是一回事,用Text
构建AST是另一回事。在返回之前,我还需要pack
String
:
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
答案 0 :(得分:20)
由于Parsec 3.1.2支持Data.Text是内置的! 见http://hackage.haskell.org/package/parsec-3.1.2
如果您遇到旧版本,其他答案中的代码片段也会有所帮助。
答案 1 :(得分:9)
这看起来就像你需要做的那样。
它应与Parsec的其余部分兼容,包括Parsec.Char解析器。
如果您使用Cabal构建程序,请在您的程序包描述中放置parsec-3.1的上限,以防维护者决定将该实例包含在Parsec的未来版本中。
答案 2 :(得分:5)
我添加了一个函数parseFromUtf8File
来帮助以有效的方式读取UTF-8编码的文件。与变音字符完美配合。函数类型与parseFromFile
中的Text.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 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)