我正在尝试使用fparsec解析一个简单的待办事项列表语言(实际上来自TaskPaper的数据)作为一个简单的解析器组合示例。但是我遇到了一个我似乎无法解开的错误。我是解析器组合器的新手,而FParsec似乎依赖于我知道Parsec,但我发现parsec文档难以理解。
任务纸语言的规则很简单(我现在忽略@tags)
所以字符串“Project 1:\ n Some note \ nProject 2:”应该从parseFile返回为[ProjectName(“Project 1”); NoteText(“Some note”); ProjectName(“Project 2”)],但是相反,我得到[ProjectName(“Project 1”); ProjectName(“Some note \ nProject 2”)]
以下是我的解析器代码。
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)
被修改
语法来自Hogbay Software的TaskPaper应用程序TaskPaper website 一些语法示例
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
答案 0 :(得分:3)
我对FParsec不是很流利,但是这个有效:
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
打印出来:
[ProjectName "Project 1"; NoteText "Some note"; ProjectName "Project 2"; TaskText "One Task"]
我会根据其他例子进行测试。
BTW:我使用FParsec的几次我更喜欢组合风格而不是monadic风格。