【问题标题】:Use FParsec to parse float or int*float使用 FParsec 解析 float 或 int*float
【发布时间】:2016-02-02 11:02:52
【问题描述】:

我刚刚开始玩 FParsec,现在我正在尝试解析以下格式的字符串

10*0.5 0.25 0.75 3*0.1 0.9

我想把3*0.1,比如,扩展成0.1 0.1 0.1

到目前为止,我有以下内容

type UserState = unit
type Parser<'t> = Parser<'t, UserState>

let str s : Parser<_> = pstring s

let float_ws : Parser<_> = pfloat .>> spaces

let product = pipe2 pint32 (str "*" >>. float_ws) (fun x y -> List.init x (fun i -> y)) 

产品解析器正确解析 int*float 格式的条目并将其扩展为浮点数列表。但是,我无法想出一个允许我解析int*float 或只是一个浮点数的解决方案。我想做类似的事情

many (product <|> float_ws)

这当然行不通,因为解析器的返回类型不同。关于如何使这项工作的任何想法?是否可以修改 float_ws 使其返回一个只有一个浮点数的列表?

【问题讨论】:

    标签: f# fparsec


    【解决方案1】:

    您可以通过简单地添加|&gt;&gt; List.singleton 来使float_ws 返回float list

    let float_ws : Parser<_> = pfloat .>> spaces |>> List.singleton
    

    |&gt;&gt; 只是map 函数,您可以在其中将某个函数应用于一个解析器的结果并接收某个新类型的新解析器:

    val (|>>): Parser<'a,'u> -> ('a -> 'b) -> Parser<'b,'u>
    

    见:http://www.quanttec.com/fparsec/reference/primitives.html#members.:124::62::62


    另外,由于product 解析器包含一个int 解析器,它会成功地从错误的大小写中解析一个字符,这意味着解析器的状态将会改变。这意味着您不能直接在第一个解析器上使用&lt;|&gt; 运算符,您还必须添加attempt 以便 FParsec 可以返回到原始解析器状态。

    let combined = many (attempt product <|> float_ws)
    

    【讨论】:

    • 太好了,谢谢,|&gt;&gt; 非常有用!但是,当组合两个解析器并在测试字符串上运行它时,我确实遇到了错误。我的组合解析器是let combined = many (product &lt;|&gt; float_ws_list),我在其中定义了let float_ws_list : Parser&lt;_&gt; = pfloat .&gt;&gt; spaces |&gt;&gt; List.singleton。我测试它的字符串是"3*0.5 0.75"
    • 我返回并重新阅读了&lt;|&gt; 运算符的文档并意识到如果第一个解析器更改解析器状态,它将失败并且不会尝试第二个解析器。我通过使用 attempt 解决了:let combined = many (attempt product &lt;|&gt; float_ws_list)
    • @Chepe 我只是在您的评论出现时输入它:) 我已经更新了答案以包含该信息。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2011-10-11
    • 2022-11-27
    • 2019-06-24
    • 2016-02-18
    • 1970-01-01
    • 1970-01-01
    • 2011-05-28
    相关资源
    最近更新 更多