匹配多个 ParserResult 并提取值
Matching More than One ParserResult and Extracting Values
这是一个关于使用 FParsec 的 ParserResult 的问题。
是否有更清晰的 match_result
实现来提取 ParserResult
中包含的 XKEYVALUE
或 XATTRIBUTES
而无需两个嵌套匹配项?
以下代码用作 F# 控制台应用程序...
// Learn more about F# at http://fsharp.org
open System
open FParsec
// Types
type XKEYVALUE = string * string
type XATTRIBUTES = Map< string, string>
type PARSER_RESULT_XML =
| PR_XKEYVALUE of ParserResult<XKEYVALUE, unit>
| PR_XATTRIBUTES of ParserResult<XATTRIBUTES, unit>
// Parser Trace
let (<!>) (p: Parser<_,_>) label : Parser<_,_> =
fun stream ->
printfn "%A: Entering %s" stream.Position label
let reply = p stream
do
match (reply.Status) with
| Ok -> printfn "%A: Leaving %s (%A) - %A" stream.Position label reply.Status reply.Result
| Error -> printfn "%A: Leaving %s (%A) - %A" stream.Position label reply.Status reply.Error
| FatalError -> printfn "%A: Leaving %s with FatalError (%A)" stream.Position label reply.Status
| _ -> printfn "%A: Leaving %s with unknown status" stream.Position label
reply
// Parsers
let ws = spaces
let str = pstring
let xKey : Parser<string,unit> = (ws >>. regex "[a-zA-Z][a-zA-Z0-9:]*") <!> "xKey"
let xStringLiteral = regex "[^\"]+" <!> "xStringLiteral"
let xKeyValue : Parser<XKEYVALUE, unit> =
ws >>. xKey .>>. (ws >>. str "=" >>. ws >>. str "\"" >>. xStringLiteral .>> str "\"" .>> ws) |>> XKEYVALUE <!> "xKeyValue"
let xAttributes : Parser<XATTRIBUTES, unit> = sepEndBy xKeyValue ws |>> XATTRIBUTES <!> "xAttributes"
// Test Data
let xKeyValue_text = """ key = "value" aa"""
let xAttributes_text = "key1=\"value1\" key2=\"value2\""
let match_result ( result : PARSER_RESULT_XML) : string =
match result with
| PR_XKEYVALUE(a) -> match a with
| Success( ((key : string), (value : string)), x2, x3) -> sprintf "%s=\"%s\"" key value
| Failure( _, _, _) -> sprintf "FAILURE"
| PR_XATTRIBUTES( a) -> match a with
| Success( (x1 : Map<string, string>), x2, x3) -> sprintf "x1=%A, x2=%A, x3=%A" x1 x2 x3
| Failure( _, _, _) -> sprintf "FAILURE"
[<EntryPoint>]
let main argv =
run xKeyValue xKeyValue_text |> PR_XKEYVALUE |> match_result |> printfn "%A"
run xAttributes xAttributes_text |> PR_XATTRIBUTES |> match_result |> printfn "%A"
0 // return an integer exit code
但是 match_result
的嵌套匹配看起来很笨拙。
一个失败的实验是使用 AND pattern match 将 PARSER_RESULT_XML & Success( …)
的匹配放在同一个匹配表达式中,但我无法使两个匹配表达式的类型一致。
您将如何修改 match_result
以做得更好或更干净?
这对我来说是主观的,但如果你去掉不需要的类型注释并更改 match_result 上的缩进,我认为它会稍微提高可读性。
let match_result result =
match result with
| PR_XKEYVALUE a ->
match a with
| Success ((key, value), _, _) -> sprintf "%s=\"%s\"" key value
| Failure _ -> sprintf "FAILURE"
| PR_XATTRIBUTES a ->
match a with
| Success (x1, x2, x3) -> sprintf "x1=%A, x2=%A, x3=%A" x1 x2 x3
| Failure _ -> sprintf "FAILURE"
如果您对此仍然不满意,您可能会发现在此处使用活动模式很有帮助:
let (|KeyValue|Attributes|Failed|) result =
match result with
| PR_XKEYVALUE a ->
match a with
| Success ((key, value), _, _) -> KeyValue (key, value)
| Failure _ -> Failed
| PR_XATTRIBUTES a ->
match a with
| Success (x1, x2, x3) -> Attributes (x1, x2, x3)
| Failure _ -> Failed
let match_result result =
match result with
| KeyValue (key, value) -> sprintf "%s=\"%s\"" key value
| Attributes (x1, x2, x3) -> sprintf "x1=%A, x2=%A, x3=%A" x1 x2 x3
| Failed -> sprintf "FAILURE"
后者更好,因为您将以领域术语解释结果,以及如何处理它(在本例中为打印消息)。
您可以根据需要对结构进行模式匹配:
let match_result result =
match result with
| PR_XKEYVALUE (Success ((key, value), _, _)) -> sprintf "%s=\"%s\"" key value
| PR_XATTRIBUTES (Success (x1, x2, x3)) -> sprintf "x1=%A, x2=%A, x3=%A" x1 x2 x3
| _ -> "FAILURE"
这是一个关于使用 FParsec 的 ParserResult 的问题。
是否有更清晰的 match_result
实现来提取 ParserResult
中包含的 XKEYVALUE
或 XATTRIBUTES
而无需两个嵌套匹配项?
以下代码用作 F# 控制台应用程序...
// Learn more about F# at http://fsharp.org
open System
open FParsec
// Types
type XKEYVALUE = string * string
type XATTRIBUTES = Map< string, string>
type PARSER_RESULT_XML =
| PR_XKEYVALUE of ParserResult<XKEYVALUE, unit>
| PR_XATTRIBUTES of ParserResult<XATTRIBUTES, unit>
// Parser Trace
let (<!>) (p: Parser<_,_>) label : Parser<_,_> =
fun stream ->
printfn "%A: Entering %s" stream.Position label
let reply = p stream
do
match (reply.Status) with
| Ok -> printfn "%A: Leaving %s (%A) - %A" stream.Position label reply.Status reply.Result
| Error -> printfn "%A: Leaving %s (%A) - %A" stream.Position label reply.Status reply.Error
| FatalError -> printfn "%A: Leaving %s with FatalError (%A)" stream.Position label reply.Status
| _ -> printfn "%A: Leaving %s with unknown status" stream.Position label
reply
// Parsers
let ws = spaces
let str = pstring
let xKey : Parser<string,unit> = (ws >>. regex "[a-zA-Z][a-zA-Z0-9:]*") <!> "xKey"
let xStringLiteral = regex "[^\"]+" <!> "xStringLiteral"
let xKeyValue : Parser<XKEYVALUE, unit> =
ws >>. xKey .>>. (ws >>. str "=" >>. ws >>. str "\"" >>. xStringLiteral .>> str "\"" .>> ws) |>> XKEYVALUE <!> "xKeyValue"
let xAttributes : Parser<XATTRIBUTES, unit> = sepEndBy xKeyValue ws |>> XATTRIBUTES <!> "xAttributes"
// Test Data
let xKeyValue_text = """ key = "value" aa"""
let xAttributes_text = "key1=\"value1\" key2=\"value2\""
let match_result ( result : PARSER_RESULT_XML) : string =
match result with
| PR_XKEYVALUE(a) -> match a with
| Success( ((key : string), (value : string)), x2, x3) -> sprintf "%s=\"%s\"" key value
| Failure( _, _, _) -> sprintf "FAILURE"
| PR_XATTRIBUTES( a) -> match a with
| Success( (x1 : Map<string, string>), x2, x3) -> sprintf "x1=%A, x2=%A, x3=%A" x1 x2 x3
| Failure( _, _, _) -> sprintf "FAILURE"
[<EntryPoint>]
let main argv =
run xKeyValue xKeyValue_text |> PR_XKEYVALUE |> match_result |> printfn "%A"
run xAttributes xAttributes_text |> PR_XATTRIBUTES |> match_result |> printfn "%A"
0 // return an integer exit code
但是 match_result
的嵌套匹配看起来很笨拙。
一个失败的实验是使用 AND pattern match 将 PARSER_RESULT_XML & Success( …)
的匹配放在同一个匹配表达式中,但我无法使两个匹配表达式的类型一致。
您将如何修改 match_result
以做得更好或更干净?
这对我来说是主观的,但如果你去掉不需要的类型注释并更改 match_result 上的缩进,我认为它会稍微提高可读性。
let match_result result =
match result with
| PR_XKEYVALUE a ->
match a with
| Success ((key, value), _, _) -> sprintf "%s=\"%s\"" key value
| Failure _ -> sprintf "FAILURE"
| PR_XATTRIBUTES a ->
match a with
| Success (x1, x2, x3) -> sprintf "x1=%A, x2=%A, x3=%A" x1 x2 x3
| Failure _ -> sprintf "FAILURE"
如果您对此仍然不满意,您可能会发现在此处使用活动模式很有帮助:
let (|KeyValue|Attributes|Failed|) result =
match result with
| PR_XKEYVALUE a ->
match a with
| Success ((key, value), _, _) -> KeyValue (key, value)
| Failure _ -> Failed
| PR_XATTRIBUTES a ->
match a with
| Success (x1, x2, x3) -> Attributes (x1, x2, x3)
| Failure _ -> Failed
let match_result result =
match result with
| KeyValue (key, value) -> sprintf "%s=\"%s\"" key value
| Attributes (x1, x2, x3) -> sprintf "x1=%A, x2=%A, x3=%A" x1 x2 x3
| Failed -> sprintf "FAILURE"
后者更好,因为您将以领域术语解释结果,以及如何处理它(在本例中为打印消息)。
您可以根据需要对结构进行模式匹配:
let match_result result =
match result with
| PR_XKEYVALUE (Success ((key, value), _, _)) -> sprintf "%s=\"%s\"" key value
| PR_XATTRIBUTES (Success (x1, x2, x3)) -> sprintf "x1=%A, x2=%A, x3=%A" x1 x2 x3
| _ -> "FAILURE"