gpt4 book ai didi

f# - 使用 FParsec 解析 int 或 float

转载 作者:行者123 更新时间:2023-12-04 20:36:10 25 4
gpt4 key购买 nike

我正在尝试使用 FParsec 解析一个文件,该文件由 float 或 int 值组成。我面临两个找不到好的解决方案的问题。

1

两者 pint32pfloat将成功解析相同的字符串,但给出不同的答案,例如 pint32将返回 3解析字符串时 "3.0"pfloat将返回 3.0解析相同的字符串时。是否可以尝试使用 pint32 解析浮点值?如果字符串是 "3.0" 则失败?

换句话说,有没有办法使以下代码工作:

let parseFloatOrInt lines =
let rec loop intvalues floatvalues lines =
match lines with
| [] -> floatvalues, intvalues
| line::rest ->
match run floatWs line with
| Success (r, _, _) -> loop intvalues (r::floatvalues) rest
| Failure _ ->
match run intWs line with
| Success (r, _, _) -> loop (r::intvalues) floatvalues rest
| Failure _ -> loop intvalues floatvalues rest

loop [] [] lines

这段代码将正确地将所有浮点值放入 floatvalues列表,但因为 pfloat返回 "3.0"解析字符串时 "3" ,所有整数值也将被放入 floatvalues列表。

2

上面的代码示例对我来说似乎有点笨拙,所以我猜一定有更好的方法来做到这一点。我考虑使用 choice 将它们组合起来,但是两个解析器必须返回相同的类型才能工作。我想我可以创建一个有区别的联合,一个选项用于 float 一个选项用于 int 并转换来自 pint32 的输出和 pfloat使用 |>>运算符(operator)。但是,我想知道是否有更好的解决方案?

最佳答案

您在考虑定义域数据和分离解析器的定义及其对源数据的使用方面走在正确的道路上。这似乎是一个很好的方法,因为随着您的实际项目进一步发展,您可能需要更多的数据类型。

这是我将如何编写它:

/// The resulting type, or DSL
type MyData =
| IntValue of int
| FloatValue of float
| Error // special case for all parse failures

// Then, let's define individual parsers:
let pMyInt =
pint32
|>> IntValue

// this is an alternative version of float parser.
// it ensures that the value has non-zero fractional part.
// caveat: the naive approach would treat values like 42.0 as integer
let pMyFloat =
pfloat
>>= (fun x -> if x % 1 = 0 then fail "Not a float" else preturn (FloatValue x))
let pError =
// this parser must consume some input,
// otherwise combined with `many` it would hang in a dead loop
skipAnyChar
>>. preturn Error

// Now, the combined parser:
let pCombined =
[ pMyFloat; pMyInt; pError ] // note, future parsers will be added here;
// mind the order as float supersedes the int,
// and Error must be the last
|> List.map (fun p -> p .>> ws) // I'm too lazy to add whitespase skipping
// into each individual parser
|> List.map attempt // each parser is optional
|> choice // on each iteration, one of the parsers must succeed
|> many // a loop

请注意,上面的代码能够处理任何来源:字符串、流或其他任何来源。您的真实应用程序可能需要处理文件,但只需使用 string list 就可以简化单元测试。 .
// Now, applying the parser somewhere in the code:
let maybeParseResult =
match run pCombined myStringData with
| Success(result, _, _) -> Some result
| Failure(_, _, _) -> None // or anything that indicates general parse failure

更新。我已经根据评论编辑了代码。 pMyFloat已更新以确保解析的值具有非零小数部分。

关于f# - 使用 FParsec 解析 int 或 float,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/35174054/

25 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com