【问题标题】:FParsec Parsing list with optional content, fails on continuing with next parser具有可选内容的 FParsec 解析列表,无法继续使用下一个解析器
【发布时间】:2020-05-04 16:46:26
【问题描述】:

我正在尝试解析资产类型列表,其中每种资产类型都可能具有名称。列表完成后,我想继续解析资产类型的属性列表,所有资产类型的列表。

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

在我看来,它似乎正在尝试在属性字符串上失败的 opt 资产名称解析器,但我不确定如何忽略它并在列表“完成”时继续前进(毕竟资产名称部分是可选的)..

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"

【问题讨论】:

  • 可能是最后一行字符串中的错字吗?它缺少c,因为它以onverter 而不是converter 开头。我不知道这是否有帮助:)
  • 不幸的是我的复制/粘贴中的一个错字。解析没有属性的资产类型和名称按预期工作。
  • 那么您需要专家的帮助:)

标签: f# fparsec


【解决方案1】:

编辑 正如similar answer 中所讨论的以及documentation 中所暗示的,如果p 在更改其状态后失败,则可选解析器opt p 将失败。相反,应该使用回溯(恢复状态),或者使用 attempt 解析器,或者使用回溯运算符之一。

记住opt (attempt (p &gt;&gt;. q))等同于opt (p &gt;&gt;? q),试试

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

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

资产类型: |转换器 |信号塔 |动力单元

命名资产: | 资产类型 | 资产类型 命名 身份

资产清单命名资产,...,命名资产

归属资产列表资产列表 属性 身份列表

以下行不重复 named-asset 的解析器。

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"])

【讨论】:

  • 谢谢,这很接近,但如果最后一个资产只是 powerunit.. ``` "converter named a023, signaltower, powerunit attributes- power, temperature" |> run p |> printfn "%A" //Failure: //Error in Ln: 1 Col: 46 //converter named a023, signaltower, powerunit attributes power, temperature // ^ //Expecting: 'named' val it : unit = () ` ``
  • @hsulriksen 一分钱下降。我们可能在这里需要一些backtrackinglet assetName = spaces1 &gt;&gt;? (named |&gt;&gt; AssetName)
  • 谢谢!我试过用>>?和>>.?但在错误的地方(而不是选择)。现在我只需要在我的头脑中将其解码为一些逻辑。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2021-07-16
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2017-05-30
相关资源
最近更新 更多