FParsec und eine Delimiter basierte Syntax
Frage
Ich versuche FParsec zu verwenden, um eine einfache ToDo-Liste Sprache (die Daten aus Taskpaper tatsächlich) als einfaches Parser combinator Beispiel zu analysieren. Aber ich habe in einen Fehler laufen ich nicht herauszubekommen scheinen kann. Ich bin neu in Parser Kombinatoren und FParsec scheint auf mich zu wissen, Parsec zu verlassen, aber ich bin der Parsec Dokumentation unergründlich zu finden.
Die Regeln der Aufgabe Papier Sprache einfach sind (ich ignoriere @tags jetzt) ??
- Projekte enden mit einem ':'
- Die Aufgaben werden beginnen mit '-'
- Jede andere Textzeile ist eine Nur-Text Hinweis auf entweder das Projekt oder eine Aufgabe
So die Zeichenfolge "Projekt 1: \ nEinige note \ nProject 2:" von parseFile zurückkehren sollte als [Projektname ( "Projekt 1"); Notetext ( "Some Note"); Projektnamen ( "Projekt 2")], aber stattdessen ich [Projektname ( "Projekt 1"); Projektname ( "Some Note \ nProject 2")]
Unten ist mein Parsercode.
open FParsec.Primitives
open FParsec.CharParsers
type ProjectAst = ProjectName of string
| TaskText of string
| NoteText of string
let asString (x:char list) :string =
x
|> List.map (fun y -> y.ToString())
|> String.concat ""
let makeNote x = NoteText(asString x)
let parseProject =
parse { let! s = many (noneOf ":\n\r\c")
do! skipChar ':'
return ProjectName( asString s ) }
let parseTask =
parse { do! skipChar '-'
let! s = many (noneOf "\n\r\c")
return TaskText( asString s) }
let parseNote = many (noneOf "\n\r\c") |>> makeNote
let parseLine = parseTask <|> (attempt parseProject) <|> parseNote
let parseFile = sepBy parseLine (many1 whitespace)
Edited
Die Syntax von Hogbay Software Taskpaper Anwendung genommen wird Taskpaper Website Einige Beispiele für die Syntax
Project 1: Description of Project One -task for project 1 -another task for project 1 details for another task -final task Go to store: -buy eggs -buy milk
Lösung
Ich bin nicht super fließend FParsec, aber diese funktioniert:
let newline = pchar '\n'
let notNewLine = noneOf "\n"
let allTillEOL = manyChars notNewLine
let parseProject =
let r = manyCharsTill (noneOf ":\n") (pchar ':')
r |>> ProjectName
let parseTask =
let r = skipChar '-' >>. allTillEOL
r |>> TaskText
let parseNote = allTillEOL |>> NoteText
let parseLine = parseTask <|> attempt parseProject <|> parseNote
let parseFile = sepBy parseLine newline
let a = run parseFile "Project 1:\nSome note\nProject 2:\n-One Task"
match a with
| Success (a,b,c) -> printfn "%A" a
| Failure (a,b,c) -> printfn "failed: %s" a
druckt:
[ProjectName "Project 1"; NoteText "Some note"; ProjectName "Project 2"; TaskText "One Task"]
ich es gegen andere Beispiele testen würde.
BTW:. Die wenigen Male, die ich FParsec ich verwendet habe, habe die combinator Stil über monadischen Stil bevorzugt