具有 2 种模式之一的 FParsec 匹配字符串

FParsec match string which have one of 2 patterns

我正在尝试学习 FParsec 并尝试匹配遵循两种模式的字符串。 该字符串可以是普通字符串,如 "string",也可以是带一个点的字符串,如 "st.ring".

解析器应如下所示:Parser<(string Option * string),unit>。第一个字符串是可选的,具体取决于字符串是否被点分隔。可选字符串表示 ".".

之前的字符串部分

我尝试了一些不同的东西,但我觉得这次尝试是结束:

let charstilldot = manyCharsTill anyChar (pstring ".")
let parser = opt(charstilldot) .>>. (many1Chars anyChar)

这适用于这样的输入 "st.ring" 但不适用于 "string" 因为后者不存在点。

非常感谢您的帮助,谢谢!

编辑: 我有一个解决方案,它基本上按顺序解析参数并根据它们是否在字符串

中是一个点来交换参数
let colTargetWithoutDot : Parser<string Option,unit> = spaces |>> fun _ -> None
let colTargetWithDot = (pstring "." >>. alphastring) |>> Some
let specificColumn = alphastring .>>. (colTargetWithDot <|> colTargetWithoutDot) |>> (fun (h,t) ->
    match h,t with
    | h,None -> (None,h)
    | h,Some(t) -> (Some(h),t))

但是这不是很好,所以我仍然会推荐另一个解决方案!

我认为这里的主要问题是 charstilldot 即使失败也会消耗字符。在这种情况下,many1chars 会失败,因为整个输入已被消耗。解决此问题的最简单方法是在没有点时使用 attempt 回滚:

let charstilldot = attempt (manyCharsTill anyChar (pstring "."))
let parser = opt(charstilldot) .>>. (many1Chars anyChar)

结果:

  • "str.ing" -> (Some "str", "ing")
  • "string" -> (None, "string")

我认为还有其他好的解决方案,但我已尝试为您提供一个需要对当前代码进行最少更改的解决方案。