我在尝试用FParsec解析类似json的同构数组时遇到了一个问题。我已经将这个问题分解成一个简短的例子来再现它。
#r @"..\packages\FParsec.1.0.2\lib\net40-client\FParsecCS.dll"
#r @"..\packages\FParsec.1.0.2\lib\net40-client\FParsec.dll"
open System
open FParsec
let test p str =
match run p str with
| Success(result, _, _) -> printfn "Success: %A" result
| Failure(errormsg, _, _) -> printfn "Failure: %s" errormsg
type CValue = CInt of int64
| CBool of bool
| CList of CValue list
let P_WHITESPACE = spaces
let P_COMMA = pstring ","
let P_L_SBRACE = pstring "[" .>> P_WHITESPACE
let P_R_SBRACE = P_WHITESPACE >>. pstring "]"
let P_INT_VALUE = pint64 |>> CInt
let P_TRUE = stringReturn "true" (CBool true)
let P_FALSE = stringReturn "false" (CBool false)
let P_BOOL_VALUE = P_TRUE <|> P_FALSE
let P_LIST_VALUE =
let commaDelimitedList ptype = sepBy (ptype .>> P_WHITESPACE) (P_COMMA .>> P_WHITESPACE)
let delimitedList = (commaDelimitedList P_INT_VALUE) <|> (commaDelimitedList P_BOOL_VALUE)
let enclosedList = between P_L_SBRACE P_R_SBRACE delimitedList
enclosedList |>> CList当我使用test函数来试用它时,我得到了以下结果:
test P_LIST_VALUE "[1,2,3]"
Success: CList [CInt 1L; CInt 2L; CInt 3L]
test P_LIST_VALUE "[true,false]"
Failure: Error in Ln: 1 Col: 2
[true,false]
^
Expecting: integer number (64-bit, signed) or ']'如果我在使用<|>运算符时交换了P_INT_VALUE和P_BOOL_VALUE的顺序,则[true,false]解析成功,但[1,2,3]失败,并显示类似的错误。所以基本上,我首先使用的解析器就是它试图使用的。
我知道如果LHS改变了用户状态,<|>操作符不会尝试RHS解析器--但我不明白这是怎么发生的。P_BOOL_VALUE和P_INT_VALUE没有任何共同的起始字符,所以当尝试解析错误的数据类型时,两者都应该立即失败。整数从不以'false‘或'true’开头,布尔从不以数字开头。
我做错了什么?
发布于 2016-09-13 18:46:42
啊,我想通了。错误消息中的提示是or ']'。问题是sepBy在空输入上成功,所以当它命中t时,它会成功返回一个空列表,然后控制传递回between,它试图找到一个终止的],但失败了。
解决方案是将空列表大小写移出特定于int/bool的解析器,如下所示:
let P_LIST_VALUE =
let commaDelimitedList ptype = sepBy1 (ptype .>> P_WHITESPACE) (P_COMMA .>> P_WHITESPACE)
let delimitedList = (commaDelimitedList P_INT_VALUE) <|> (commaDelimitedList P_BOOL_VALUE) <|> preturn []
let enclosedList = between P_L_SBRACE P_R_SBRACE delimitedList
enclosedList |>> CList请注意,这里使用了sepBy1而不是sepBy,并且添加了<|> preturn []以在delimitedList中只处理一次空案例。
顺便说一句,我不知道您的确切应用程序,但在解析器中强制输入通常不是一个好主意;实现这一点的一种更常见的方法是(使用原始commaDelimitedList)解析commaDelimitedList (P_INT_VALUE <|> P_BOOL_VALUE),然后在后续分析阶段检查输入。
https://stackoverflow.com/questions/39460379
复制相似问题