FParsec を使用して、独自の形式を記述する入力を解析しています。たとえば、次の入力を検討してください。
int,str,int:4,'hello',3
入力の最初の部分 (コロンの前) は、入力の 2 番目の部分の形式を記述します。この場合、形式はint
, str
,ですint
。これは、実際のデータが指定された型の 3 つのカンマ区切りの値で構成されることを意味するため、結果は4
, "hello"
, になり3
ます。
FParsec でこのようなものを解析する最良の方法は何ですか?
以下に最善を尽くしましたが、満足していません。parse
よりクリーンで、ステートフルでなく、モナドへの依存度が低い、これを行うためのより良い方法はありますか? これは 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