2010-11-23 32 views
1

我想使用fparsec來解析簡單的待辦事項列表語言(實際上來自TaskPaper的數據)作爲簡單的分析程序組合器示例。但是我遇到了一個我似乎無法解決的bug。我是分析器組合器的新手,FParsec似乎依賴於我瞭解Parsec,但我發現parsec文檔不可思議。FParsec和基於分隔符的語法

任務紙張語言的規則很簡單(我忽略@tags現在)

  • 項目「結尾:」
  • 任務將開始「 - 」
  • 任何其他行文本是項目或任務上的純文本註釋

因此,字符串「Project 1:\ nSome note \ nProject 2:」應該從parseFile返回爲[ProjectName(「Project 1」); NoteText(「Some note」); ProjectName(「Projec t 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軟件的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

我跑的代碼,並得到`[NoteText「Proje」]` – 2010-11-23 03:40:29

+0

你可以發佈這種格式的代表性樣本? – 2010-11-23 03:43:30

回答

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"] 

我會對其他例子進行測試。

順便說一句:我已經使用過幾次FParsec我更喜歡一元風格的combinator風格。