我正在使用 FParsec 来解析描述其自身格式的输入。例如,考虑这个输入:
int,str,int:4,'hello',3
输入的第一部分(冒号之前)描述了输入第二部分的格式。在这种情况下,格式是int
, str
, int
,这意味着实际数据由给定类型的三个逗号分隔值组成,因此结果应该是4
, "hello"
, 3
。
使用 FParsec 解析此类内容的最佳方法是什么?
我已经在下面粘贴了我的最大努力,但我对此并不满意。有没有更好的方法来做到这一点,更干净,更少有状态,更少依赖于parse
monad?我认为这取决于对 UserState 的更智能管理,但我不知道该怎么做。谢谢。
open FParsec
type State = { Formats : string[]; Index : int32 }
with static member Default = { Formats = [||]; Index = 0 }
type Value =
| Integer of int
| String of string
let parseFormat : Parser<_, State> =
parse {
let! formats =
sepBy
(pstring "int" <|> pstring "str")
(skipString ",")
|>> Array.ofList
do! updateUserState (fun state -> { state with Formats = formats })
}
let parseValue format =
match format with
| "int" -> pint32 |>> Integer
| "str" ->
between
(skipString "'")
(skipString "'")
(manySatisfy (fun c -> c <> '\''))
|>> String
| _ -> failwith "Unexpected"
let parseValueByState =
parse {
let! state = getUserState
let format = state.Formats.[state.Index]
do! setUserState { state with Index = state.Index + 1}
return! parseValue format
}
let parseData =
sepBy
parseValueByState
(skipString ",")
let parse =
parseFormat
>>. skipString ":"
>>. parseData
[<EntryPoint>]
let main argv =
let result = runParserOnString parse State.Default "" "int,str,int:4,'hello',3"
printfn "%A" result
0