下面的示例代码看起来很好用:
open FParsec
let capitalized : Parser<unit,unit> =(asciiUpper >>. many asciiLower >>. eof)
let inverted : Parser<unit,unit> =(asciiLower >>. many asciiUpper >>. eof)
let capsOrInvert =choice [capitalized;inverted]
然后,您可以执行以下操作:
run capsOrInvert "Dog";;
run capsOrInvert "dOG";;
并获得成功或:
run capsOrInvert "dog";;
并失败了。
现在我有了一个ParserResult,该如何处理呢?例如,向后打印字符串?
最佳答案
您的代码有几个明显的问题。
首先,正如@scrwtp的答案所指出的,您的解析器将返回unit
。 原因如下:运算符(>>.)
仅返回右侧内部解析器返回的结果。另一方面,(.>>)
将返回左分析器的结果,而(.>>.)
将返回左和右两个元组。
因此,parser1 >>. parser2 >>. eof
本质上是(parser1 >>. parser2) >>. eof
。
parens中的代码将完全忽略parser1
的结果,然后第二个(>>.)
将忽略parens中的解析器的整个结果。最后,eof
返回unit
,并将返回此值。
您可能需要返回一些有意义的数据,例如解析的字符串。最简单的方法是:
let capitalized = (asciiUpper .>>. many asciiLower .>> eof)
注意运算符(operator)。
inverted
的代码可以类似的方式完成。该解析器的类型为
Parser<(char * char list), unit>
,第一个字符的元组和所有其余字符的元组,因此您可能需要将它们合并回。有几种方法可以做到这一点,这是一种:let mymerge (c1: char, cs: char list) = c1 :: cs // a simple cons
let pCapitalized = capitalized >>= mymerge
该代码的优点在于,您的
mymerge
是正常函数,与普通char
一起使用时,它对解析器一无所知。它仅适用于数据,其余的由(>>=)
运算符完成。注意,
pCapitalized
也是一个解析器,但是它返回一个char list
。没有什么可以阻止您从应用进一步的转换。正如您提到的向后打印字符串:
let pCapitalizedAndReversed =
capitalized
>>= mymerge
>>= List.rev
我已经为此目的编写了代码。在不同的行中,您看到域数据的逐渐过渡,仍在Parser 范式之内。这是一个重要的考虑因素,因为例如任何后续转换都可能“出于某种原因”确定数据是错误的,并引发解析异常。或者,可以将其与其他解析器合并。
一旦您的域数据(已解析的单词)完成,就可以提取另一个答案中提到的结果。
小调。
choice
仅对于两个解析器是多余的。请改用(<|>)
。根据经验,仔细选择解析器组合器非常重要,因为在核心解析器逻辑内部进行错误的选择很容易使解析器显着变慢。有关更多详细信息,请参见FParsec Primitives。
关于f# - 使用ParserResult,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/40619561/