FParsec解析包含可选内容的列表,在继续下一个解析器时失败



我试图解析一个资产类型列表,其中每个资产类型都可能有一个名称。列表完成后,我想继续解析资产类型的属性列表,即所有资产类型的一个列表。

我试图解析的字符串如下所示:converter named a023, signaltower, powerunit named 23 attributes power, temperature解析器签名看起来像Parser<((Asset * AssetName option) list * Attribute liste),unit>我分别解析了资产名称和属性,当我将两者合并并列出时,问题就出现了,然后在声明Expecting: 'named'的属性字符串上失败了。

对我来说,它似乎在尝试opt-assetname解析器,但它在属性字符串上失败了,但我不知道如何忽略它,并在列表"完成"时继续前进(毕竟资产名称部分是可选的(。。

type AssetName = AssetName of string
let named = str "named" >>. spaces1 >>. word
let assetName = spaces1 >>. (named |>> AssetName)
type Asset = | Converter | Signaltower | Powerunit 
let assetType = ["converter"; "signaltower"; "powerunit";] |> Seq.map pstring |> choice
let findAsset = function
| "converter" -> Converter
| "signaltower" -> Signaltower
| "powerunit" -> Powerunit
| _ -> raise <| Exception "Invalid asset type"
let asset = (assetType |>> findAsset) .>>. opt assetName 
type Attribute = Attribute of string
let attribute = word |>> Attribute
let attributes = spaces1 >>. str "attributes" >>. spaces1 >>. sepBy attribute commaMaybeSpace
let p = sepBy asset (pchar ',' >>. spaces) .>>. attributes
let r input = run p3 input
r "converter named a023, signaltower, powerunit named 23 attributes power, temperature"

编辑正如类似答案中所讨论的,以及文档中所暗示的,如果p在更改其状态后失败,则可选的解析器opt p将失败。相反,应该使用回溯(恢复状态(,可以与attempt解析器一起使用,也可以与其中一个回溯运算符一起使用。

请记住,opt (attempt (p >>. q))等同于opt (p >>? q),请尝试

let assetName = spaces1 >>? (named |>> AssetName)

不确定它是否与问题有关,但示例中的解析器类型与您描述的语法不匹配。我想你想要:

资产类型:|转换器|信号电源|动力装置

命名资产:|资产类型|已命名ident的资产类型

资产列表命名资产命名资产

属性资产列表资产列表属性标识列表

下面的行不重复命名资产的解析器。

let p = asset .>>. attributes
// val p : Parser<((Asset * AssetName option) * Attribute list),unit>

你可以用代替它

let p = sepBy asset (pchar ',' >>. spaces) .>>. attributes
// val p : Parser<((Asset * AssetName option) list * Attribute list),unit>
"converter named a023, signaltower, powerunit named 23 attributes power, temperature"
|> run p |> printfn "%A" 
// Success: ([(Converter, Some (AssetName "a023")); (Signaltower, null);
//   (Powerunit, Some (AssetName "23"))],
//  [Attribute "power"; Attribute "temperature"])

相关内容

最新更新