2010-10-31 12 views
33

Sử dụng Parsec 3.1, người ta có thể phân tích một số loại nguyên liệu đầu vào:Sử dụng Parsec với Data.Text

  • [Char] với Text.Parsec.String
  • Data.ByteString với Text.Parsec.ByteString
  • Data.ByteString.Lazy với Text.Parsec.ByteString.Lazy

tôi không thấy bất kỳ điều gì cho mô-đun Data.Text. Tôi muốn phân tích cú pháp nội dung Unicode mà không bị sự thiếu hiệu quả của String. Vì vậy, tôi đã tạo các module sau đây dựa trên các mô-đun 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. Nào thì nên làm như vậy?
  2. Điều này tương thích với phần còn lại của API Parsec?

ý kiến ​​bổ sung:

tôi đã có thêm {-# LANGUAGE NoMonomorphismRestriction #-} pragma trong module phân tích cú pháp của tôi để làm cho nó làm việc.

Phân tích cú pháp Text là một điều, việc xây dựng AST với Text là một việc khác. Tôi cũng sẽ cần phải packString tôi trước khi quay trở lại:

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 

Trả lời

9

Trông giống như chính xác những gì bạn cần làm.

Cần tương thích với phần còn lại của Parsec, bao gồm trình phân tích cú pháp Parsec.Char.

Nếu bạn đang sử dụng Cabal để xây dựng chương trình của mình, hãy đặt giới hạn trên của parsec-3.1 trong mô tả gói của bạn, trong trường hợp người duy trì quyết định bao gồm cá thể đó trong phiên bản tương lai của Parsec.

+0

Nó hoạt động OK ngoại trừ các mô-đun 'Text.Parsec.Language' và' Text.Parsec.Token' được giới hạn ở 'Chuỗi'. Tôi có thể giải quyết vấn đề đó bằng cách thực hiện mã thông báo của riêng tôi. 'Text.Parsec.Language' chỉ là một tiện ích (Mondrian? Ai?). – gawi

+0

Ah! Tôi tự hỏi liệu chúng ta có thể khái quát hóa chúng với bất kỳ luồng Char nào theo cách tương thích ngược hay không. Nó không có vẻ khó, nhưng vì tôi không bao giờ sử dụng những mô-đun đó, tôi không có bất kỳ trường hợp thử nghiệm nào tốt. –

5

Tôi đã thêm hàm parseFromUtf8File để giúp đọc các tệp được mã hóa UTF-8 theo cách hiệu quả. Hoạt động hoàn hảo với các ký tự âm sắc. Loại chức năng phù hợp với parseFromFile từ Text.Parsec.ByteString. Phiên bản này sử dụng ByteStrings nghiêm ngặt.

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