Я использую FParsec для анализа ввода, который описывает его собственный формат. Например, рассмотрим этот вход:Используйте FParsec для синтаксического анализа самоописывающего ввода
int,str,int:4,'hello',3
Первая часть входа (перед двоеточием) описывает формат второй части ввода. В этом случае формат int
, str
, int
, что означает, что фактические данные состоят из трех разделенных запятыми значений данных типов, поэтому результат должен быть 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
Парсер, который испускает парсеров, довольно крут. Это кажется очень элегантным, но немного над моей головой. Можете ли вы помочь мне понять, что делает sepByList? Если вы собираетесь использовать >> = явно, не проще ли просто переключиться на монадический синтаксис? – brianberns
Я попытался переписать ваш sepByList ниже, чтобы уточнить, что он делает. Пожалуйста, дай мне знать, что ты думаешь. – brianberns
Цель sepByList - последовательно применять синтаксические анализаторы в списке 'ps', они разделяются парсером' sep'. Я избегал монады 'parse', поскольку в заявлении говорилось, что он хочет меньше полагаться на нее. Будет проверять переписывание позже. – FuleSnabel