2010-10-31 33 views
33

Parsec 3.1 Verwendung ist es möglich, verschiedene Arten von Eingaben zu analysieren:Mit Parsec mit data.text

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

I sehe nichts für das Modul Data.Text. Ich möchte Unicode-Inhalt analysieren, ohne die String Ineffizienzen zu leiden. So habe ich die folgende Modul erstellt auf der Grundlage der Text.Parsec.ByteString Modul:

{-# 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. Ist es sinnvoll, dies zu tun?
  2. Ist dies kompatibel mit dem Rest der Parsec API?

Bemerkungen:

Ich hatte {-# LANGUAGE NoMonomorphismRestriction #-} Pragma in meiner Parse-Module hinzuzufügen, damit es funktioniert.

Parsing ist eine Sache, ein AST mit Text Aufbau ist eine andere Sache. Ich muss auch meine String vor Rückkehr pack:

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 

Antwort

9

, die genau aussieht, was Sie tun müssen.

Es sollte mit dem Rest von Parsec kompatibel sein, einschließlich der Parsec.Char Parser.

Wenn Sie Cabal verwenden, um Ihr Programm zu erstellen, geben Sie eine obere Grenze von Parsec-3.1 in Ihre Paketbeschreibung ein, falls der Betreuer entscheidet, diese Instanz in eine zukünftige Version von Parsec aufzunehmen.

+0

Es funktioniert OK, außer für die Module 'Text.Parsec.Language' und' Text.Parsec.Token', die auf 'String' beschränkt sind. Ich kann dieses Problem umgehen, indem ich meine eigene Tokenisierung durchführe. 'Text.Parsec.Language' ist sowieso nur ein Gadget (Mondrian? Irgendjemand?). – gawi

+0

Ah! Ich frage mich, ob wir diese auf irgendeinen Char-Stream rückwärtskompatibel verallgemeinern können. Es sieht nicht schwer aus, aber da ich diese Module nie benutze, habe ich keine guten Testfälle. –

5

Ich habe eine Funktion parseFromUtf8File hinzugefügt, um das Lesen von UTF-8-codierten Dateien in einer effizienten Weise zu helfen. Funktioniert einwandfrei mit Umlautzeichen. Funktionstyp entspricht parseFromFile von Text.Parsec.ByteString. Diese Version verwendet strikte 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) 
Verwandte Themen