使用解析结果
Using ParserResult
下面的示例代码似乎运行良好:
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,我该如何处理它?例如,向后打印字符串?
ParserResult
是有区别的工会。您只需匹配 Success
和 Failure
案例。
let r = run capsOrInvert "Dog"
match r with
| Success(result, _, _) -> printfn "Success: %A" result
| Failure(errorMsg, _, _) -> printfn "Failure: %s" errorMsg
但这可能不是您对您的情况感到棘手的地方。
关于您的 Parser<unit, unit>
类型的事情是解析值是 unit
类型(Parser
的第一个类型参数)。这意味着这个解析器实际上并没有产生任何可供您使用的合理输出——它只能告诉你它是否可以解析一个字符串(在这种情况下你会得到一个 Success ((), _, _)
- 携带单个值输入 unit
) 或不输入。
您希望从这个解析器中得到什么?
编辑:这听起来很接近你想要的,或者至少你应该能够从中得到一些提示。 capitalized
接受大写字符串,inverted
接受已反转的大写字符串并将它们反转为解析器逻辑的一部分。
let reverse (s: string) =
System.String(Array.rev (Array.ofSeq s))
let capitalized : Parser<string,unit> =
(asciiUpper .>>. manyChars asciiLower)
|>> fun (upper, lower) -> string upper + lower
let inverted : Parser<string,unit> =
(manyChars asciiLower .>>. asciiUpper)
|>> fun (lower, upper) -> reverse (lower + string upper)
let capsOrInvert = choice [capitalized;inverted]
run capsOrInvert "Dog"
run capsOrInvert "doG"
run capsOrInvert "dog"
您的代码有几个值得注意的问题。
首先,如@scrwtp 的回答所述,你的解析器 returns unit
. 原因如下:operator (>>.)
return 只是 return 由 right 内部解析器编辑的结果。另一方面,(.>>)
会 return left 解析器的结果,而 (.>>.)
会 return 两个 左和右。
所以,parser1 >>. parser2 >>. eof
本质上是 (parser1 >>. parser2) >>. eof
。
parens 中的代码完全忽略 parser1
的结果,而第二个 (>>.)
然后忽略 parens 中解析器的整个结果。最后,eof
returns unit
,这个值正在 returned.
您可能需要一些 有意义的数据 returned,例如解析后的字符串。最简单的方法是:
let capitalized = (asciiUpper .>>. many asciiLower .>> eof)
注意操作员。
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
也是一个解析器,但它 return 是一个单独的 char list
。
没有什么能阻止您应用进一步的转换。正如您提到的向后打印字符串:
let pCapitalizedAndReversed =
capitalized
>>= mymerge
>>= List.rev
我特意这样写代码的。在不同的行中,您会看到 域数据的逐渐过渡 , 仍在解析器的范例中 。这是一个重要的考虑因素,因为任何后续转换都可能 "decide" 数据由于某种原因而损坏并引发解析异常,例如。或者,也可以将它与其他解析器合并。
一旦您的域数据(一个解析出的词)完成,您就可以提取另一个答案中提到的结果。
小记。 choice
仅对两个解析器而言是多余的。请改用 (<|>)
。根据经验,仔细选择解析器组合器很重要,因为核心解析器逻辑深处的错误选择很容易使您的解析器显着变慢。
有关详细信息,请参阅 FParsec Primitives。
下面的示例代码似乎运行良好:
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,我该如何处理它?例如,向后打印字符串?
ParserResult
是有区别的工会。您只需匹配 Success
和 Failure
案例。
let r = run capsOrInvert "Dog"
match r with
| Success(result, _, _) -> printfn "Success: %A" result
| Failure(errorMsg, _, _) -> printfn "Failure: %s" errorMsg
但这可能不是您对您的情况感到棘手的地方。
关于您的 Parser<unit, unit>
类型的事情是解析值是 unit
类型(Parser
的第一个类型参数)。这意味着这个解析器实际上并没有产生任何可供您使用的合理输出——它只能告诉你它是否可以解析一个字符串(在这种情况下你会得到一个 Success ((), _, _)
- 携带单个值输入 unit
) 或不输入。
您希望从这个解析器中得到什么?
编辑:这听起来很接近你想要的,或者至少你应该能够从中得到一些提示。 capitalized
接受大写字符串,inverted
接受已反转的大写字符串并将它们反转为解析器逻辑的一部分。
let reverse (s: string) =
System.String(Array.rev (Array.ofSeq s))
let capitalized : Parser<string,unit> =
(asciiUpper .>>. manyChars asciiLower)
|>> fun (upper, lower) -> string upper + lower
let inverted : Parser<string,unit> =
(manyChars asciiLower .>>. asciiUpper)
|>> fun (lower, upper) -> reverse (lower + string upper)
let capsOrInvert = choice [capitalized;inverted]
run capsOrInvert "Dog"
run capsOrInvert "doG"
run capsOrInvert "dog"
您的代码有几个值得注意的问题。
首先,如@scrwtp 的回答所述,你的解析器 returns unit
. 原因如下:operator (>>.)
return 只是 return 由 right 内部解析器编辑的结果。另一方面,(.>>)
会 return left 解析器的结果,而 (.>>.)
会 return 两个 左和右。
所以,parser1 >>. parser2 >>. eof
本质上是 (parser1 >>. parser2) >>. eof
。
parens 中的代码完全忽略 parser1
的结果,而第二个 (>>.)
然后忽略 parens 中解析器的整个结果。最后,eof
returns unit
,这个值正在 returned.
您可能需要一些 有意义的数据 returned,例如解析后的字符串。最简单的方法是:
let capitalized = (asciiUpper .>>. many asciiLower .>> eof)
注意操作员。
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
也是一个解析器,但它 return 是一个单独的 char list
。
没有什么能阻止您应用进一步的转换。正如您提到的向后打印字符串:
let pCapitalizedAndReversed =
capitalized
>>= mymerge
>>= List.rev
我特意这样写代码的。在不同的行中,您会看到 域数据的逐渐过渡 , 仍在解析器的范例中 。这是一个重要的考虑因素,因为任何后续转换都可能 "decide" 数据由于某种原因而损坏并引发解析异常,例如。或者,也可以将它与其他解析器合并。
一旦您的域数据(一个解析出的词)完成,您就可以提取另一个答案中提到的结果。
小记。 choice
仅对两个解析器而言是多余的。请改用 (<|>)
。根据经验,仔细选择解析器组合器很重要,因为核心解析器逻辑深处的错误选择很容易使您的解析器显着变慢。
有关详细信息,请参阅 FParsec Primitives。