Haskell Language
Attoparsec
Suche…
Einführung
Attoparsec ist eine Parsing-Combinator-Bibliothek, die "besonders auf den effizienten Umgang mit Netzwerkprotokollen und komplizierten Text- / Binärdateiformaten abzielt".
Attoparsec bietet nicht nur Geschwindigkeit und Effizienz, sondern auch Rückverfolgung und inkrementelle Eingabe.
Seine API spiegelt genau die einer anderen Parser-Combinator-Bibliothek, Parsec, wider.
Es gibt Submodule für die Kompatibilität mit ByteString
, Text
und Char8
. Die Verwendung der Spracherweiterung OverloadedStrings
wird empfohlen.
Parameter
Art | Detail |
---|---|
Parser ia | Der Kerntyp für die Darstellung eines Parsers. i ist der String-Typ, zB ByteString . |
IResult ir | Das Ergebnis einer Analyse mit Fail i [String] String , Partial (i -> IResult ir) und Done ir als Konstruktoren. |
Kombinatoren
Die Parsing-Eingabe wird am besten durch größere Parser-Funktionen erreicht, die aus kleineren Einzelfunktionen bestehen.
Angenommen, wir wollten den folgenden Text analysieren, der die Arbeitszeit darstellt:
Montag: 0800 bis 1600 Uhr
Wir könnten diese in zwei "Token" aufteilen: den Tagesnamen "Montag" und einen Zeitabschnitt "0800" bis "1600".
Um einen Tagesnamen zu analysieren, könnten wir folgendes schreiben:
data Day = Day String day :: Parser Day day = do name <- takeWhile1 (/= ':') skipMany1 (char ':') skipSpace return $ Day name
Um den Zeitabschnitt zu analysieren, könnten wir schreiben:
data TimePortion = TimePortion String String time = do start <- takeWhile1 isDigit skipSpace end <- takeWhile1 isDigit return $ TimePortion start end
Jetzt haben wir zwei Parser für unsere einzelnen Textteile. Wir können diese in einem "größeren" Parser kombinieren, um die Arbeitsstunden eines ganzen Tages zu lesen:
data WorkPeriod = WorkPeriod Day TimePortion work = do d <- day t <- time return $ WorkPeriod d t
und dann den Parser ausführen:
parseOnly work "Monday: 0800 1600"
Bitmap - Analyse binärer Daten
Attoparsec macht das Parsen von binären Daten trivial. Angenommen diese Definitionen:
import Data.Attoparsec.ByteString (Parser, eitherResult, parse, take) import Data.Binary.Get (getWord32le, runGet) import Data.ByteString (ByteString, readFile) import Data.ByteString.Char8 (unpack) import Data.ByteString.Lazy (fromStrict) import Prelude hiding (readFile, take) -- The DIB section from a bitmap header data DIB = BM | BA | CI | CP | IC | PT deriving (Show, Read) type Reserved = ByteString -- The entire bitmap header data Header = Header DIB Int Reserved Reserved Int deriving (Show)
Wir können den Header leicht aus einer Bitmap-Datei analysieren. Hier haben wir 4 Parser-Funktionen, die den Header-Abschnitt aus einer Bitmap-Datei darstellen:
Erstens kann der DIB-Abschnitt gelesen werden, indem die ersten 2 Bytes genommen werden
dibP :: Parser DIB
dibP = read . unpack <$> take 2
Ebenso können die Größe der Bitmap, die reservierten Abschnitte und der Pixelversatz problemlos gelesen werden:
sizeP :: Parser Int sizeP = fromIntegral . runGet getWord32le . fromStrict <$> take 4 reservedP :: Parser Reserved reservedP = take 2 addressP :: Parser Int addressP = fromIntegral . runGet getWord32le . fromStrict <$> take 4
die dann zu einer größeren Parser-Funktion für den gesamten Header zusammengefasst werden kann:
bitmapHeader :: Parser Header bitmapHeader = do dib <- dibP sz <- sizeP reservedP reservedP offset <- addressP return $ Header dib sz "" "" offset