如果您不喜欢在解析后测试列表长度,那么您可以尝试切换
<|>
表达式以先测试单个项的大小写,然后使用
notFollowedBy
要确保单个项目案例与列表不匹配,请执行以下操作:
let oneThing = (one <|> two <|> three)
let separator = str "or"
let lotsOfThings = sepBy1 oneThing separator |>> LotsOfThings
let oneThingOnly = oneThing .>> (notFollowedBy separator)
let lotsSecond = (attempt oneThingOnly) <|> lotsOfThings
test lotsSecond "one or two" // Success: LotsOfThings [OneThing 1; OneThing 2]
test lotsSecond "one" // Success: OneThing 1
注意使用
attempt
分析器
oneThingOnly
. 那是因为
documentation for the
<|>
parser
状态(强调原文):
解析器
p1 <|> p2
首先应用解析器
p1
. 如果
P1
成功,结果
P1
返回。如果
P1
出现非_致命错误,并且
不更改分析器状态
,解析器
p2
已应用。
没有
尝试
在这里,“一两个”会首先尝试用
只有一个
,它将使用“one”,然后在“or”上失败,但解析器状态将被更改。这个
尝试
在尝试解析器之前,Combinator基本上会生成解析器状态的“书签”,如果解析器失败,它会返回到“书签”。所以
<和gt;
之后将看到未更改的分析器状态
attempt oneThingOnly
,然后尝试
lotsOfThings
.