fparsec键值解析器无法解析

时间:2014-07-08 04:14:52

标签: f# parsec parser-combinators fparsec

我必须编写一个解析器来解析文件中的键值对,如下所示:

  

as235 242kj25klj对:A = a1 | B = b1 | C = c1

     

kjlkjlkjlkj对:A = a2 | B = b2 | C = c2

请注意,这些行包含一些垃圾,标签和键值对。

我写的F#代码如下:

#r"FParsec.dll"

open FParsec

let parse keys label =
    let pkey = keys |> Seq.map pstring |> choice

    let pvalue = manyCharsTill anyChar (anyOf "|\n")

    let ppair = pkey .>> (skipChar '=') .>>. pvalue

    let ppairSeq = many ppair

    let pline = skipManyTill anyChar (pstring label) 
                >>. ppairSeq .>> newline

    let pfile = many (opt pline) |>> Seq.choose id

    run pfile 
    >> function
    | Success (result, _, _) -> result
    | Failure (errorMsg, _, _) -> failwith errorMsg

"""
as235 242kj25klj Pairs:A=a1|B=b1|C=c1

lkjlkjlkjlkj Pairs:A=a2|B=b2|C=c2



"""
|> parse ["A";"B";"C"] "Pairs:"
|> List.ofSeq
|> printfn "%A"

预期结果是:

[[("A","a1"); "B","b1"; "C","c1"]
 [("A","a2"); "B","b2"; "C","c2"]]

...但我得到以下错误:

System.Exception: Error: Error in Ln: 8 Col: 1
Note: The error occurred at the end of the input stream.
Expecting: any char or 'Pairs:'

关于如何修复此解析器的任何想法?

谢谢!

更新:在斯蒂芬的评论之后,我试图解决它,但没有成功。这是我期待工作的最后一次尝试,但事实并非如此。

let pkey = keys |> Seq.map pstring |> choice

let pvalue = manyCharsTill anyChar (anyOf "|\n")

let ppair = pkey .>> (skipChar '=') .>>. pvalue

let ppairSeq = manyTill ppair newline

let pnonEmptyLine =
    skipManyTill anyChar (pstring label) 
    >>. ppairSeq
    |>> Some

let pemptyLine = spaces >>. newline >>% None

let pline = pemptyLine <|> pnonEmptyLine

let pfile = manyTill pline eof |>> Seq.choose id

现在错误信息是:

Error in Ln: 2 Col: 5

    as235 242kj25klj Pairs:A=a1|B=b1|C=c1

    ^

Expecting: newline

1 个答案:

答案 0 :(得分:4)

我的一位同事找到了解决方案,我在这里发帖给其他有类似问题的人。解析器也更好,因为它不需要密钥集。我使用&#39; =&#39;的左侧作为关键和右侧的价值:

let parse label str =
    let poperand = manyChars (noneOf "=|\n") 

    let ppair = poperand .>> skipChar '=' .>>. poperand

    let ppairSeq = sepBy ppair (pchar '|')

    let pLineWithPairs = skipManyTill anyChar (pstring label) >>. ppairSeq |>> Some

    let pLineWithoutPairs = (restOfLine false) >>% None

    let pLogLine = (attempt pLineWithPairs) <|> pLineWithoutPairs

    let pfile = sepBy pLogLine newline |>> Seq.choose id

    match run pfile str with
    | Success (result, _, _) -> result
    | Failure (errorMsg, _, _) -> sprintf "Error: %s" errorMsg |> failwith