.NET Regex 用于后跟一些逗号分隔数字的指令

Posted

技术标签:

【中文标题】.NET Regex 用于后跟一些逗号分隔数字的指令【英文标题】:.NET Regex for a directive followed by some comma separated numbers 【发布时间】:2014-09-29 01:30:23 【问题描述】:

我正在尝试在 F# 中编写一个匹配此类内容的正则表达式

.float -.05, 2.4
.float 31.1234
.float -0.5, 1.0, 1.1

我正在尝试这样的事情

let matchFloat input =
    let matches = Regex(@"(\.float )?(?<float>[+-]?\d*\.\d+)").Matches(input)
    ([for m in matches -> m.Groups.["float"].Value, matches.Count > 0)

哪种有效,但我对 .double 有同样的看法,无论我的 match 表达式中的第一个是匹配的 - 因为我做了“发生 0 次或 1 次”,这意味着任一指令后面的浮点数字符串将被视为相同。

那么我如何确保 .float 存在,而不执行 input.StartsWith(...)?我知道有办法编写这个正则表达式,以便它能够适当地匹配,并且 m.Groups.["float"].Value 将只返回我需要的内容,而无需在事后删除空格或逗号。

我已经把这件事搞砸了好几个小时,只是无法让它做我想做的事。我尝试过使用lookbehind/lookahead 的东西,以及其他一些东西,但没有运气。

请帮忙! :)

【问题讨论】:

那么它应该匹配.float之后的第一对数字还是全部? 应该全部匹配 而且 .float 是强制发生的? 是的 - 我还有 .double,我需要能够区分它们。 为什么 input.StartsWith(...) 是一个糟糕的解决方案?它绝对更易读,更容易实现。 【参考方案1】:

嗯,这会让你顺利前往step 1 of fixing a Linux machine

您可以结合交替使用正向后视来将行首的.float.decimal 捕获到一个组中,然后检查哪个被捕获。后视本身对主要捕获没有贡献,因此数字仍然是“组 0”中唯一的内容。

然后是我最喜欢的技巧 - 通过在后向中添加.*(在floatdecimal 之后),您可以成功地从输入字符串返回多个匹配项,每个匹配项共享初始的.float 或@987654329 @,但随后每个都向前放大以捕获一组不同的数字。

在上面打个蝴蝶结,用一点DU型来代表这两种情况:

type DataPoint =
    | Float of string
    | Decimal of string

let parse input =
    let patt = "(?<=^\.((float)|(decimal)).*(,?\s+))[+-]?\d*\.\d+(?=\s*(,|$))"
    Regex.Matches(input, patt)
    |> Seq.cast<Match>
    |> Seq.map (fun m ->
        match (m.Groups.[2].Success, m.Groups.[3].Success) with
        | (true, false) -> Float(m.Value)
        | (false, true) -> Decimal(m.Value)
        | _ -> failwith "??")
    |> List.ofSeq

// positive cases
parse ".float -.05, 2.4"        // [Float "-.05"; Float "2.4"]
parse ".float 31.1234"          // [Float "31.1234"]
parse ".float -0.5, 1.0, 1.1"   // [Float "-0.5"; Float "1.0"; Float "1.1"]
parse ".decimal 123.456, -22.0" // [Decimal "123.456"; Decimal "-22.0"]

// negative cases, plucks out valid bits
parse ".decimal xyz,,.., +1.0, .2.3.4, -.2 "  // [Decimal "+1.0"; Decimal "-.2"]
parse ".float 1.0, 2.0-, 3."                  // [Float "1.0"]

请注意,我只是依赖组号,您可能需要更加小心并使用命名组。

另外值得注意的是,.NET 是 one of the only regex environments,它支持完全交替和 .* 在后向匹配中匹配,所以这可能不是可移植的。

编辑:我根据反馈在一定程度上强化了该模式以应对负面输入。仍然不是防弹的。

【讨论】:

实际上,您的正则表达式也匹配诸如“.float 5.4.3.,.0”之类的字符串 这是极好的反馈,完全正确!更新传入。【参考方案2】:

实际上,我看不出在这种情况下 Regex 有什么用处。使用字符串函数和系统解析函数是更易读和类型安全的方式来解析输入。从@latkin 的回答中借用 DataPoint:

open System

type DataPoint =
    | Float of float
    | Decimal of decimal

let listparse parser mapper = 
    List.choose (fun f -> match parser f with true, v -> Some (mapper v) | _ -> None)

let parse (input: string) =
    match Array.toList (input.Split([|',';' '|])) with
    | ".float"::rest -> rest |> listparse Double.TryParse Float
    | ".decimal"::rest -> rest |> listparse Decimal.TryParse Decimal
    | _ -> []

在 .TryParse() 方法中使用额外的参数,您可以轻松处理更复杂的浮点输入格式,例如指数表示法(例如 1.3E5)

【讨论】:

【参考方案3】:

试试这个 \.float [+-]?[0-9\., ]+ 并参考这个 (http://regex101.com/r/kW6zZ1/1)

【讨论】:

这有几个问题: 1. 它匹配 .float ,,,,,.float 5.4.3.,.0 等虚假字符串。 2. 它不捕获像 .float 1.5, -2.5 这样的所有有效字符串 3. 它不提供提取单个数字组的方法,正如 OP 已明确的目标。

以上是关于.NET Regex 用于后跟一些逗号分隔数字的指令的主要内容,如果未能解决你的问题,请参考以下文章

MySQL REGEX匹配逗号分隔列表

逗号分隔值循环使用硬编码值但不使用参数值

Java Regex - 拆分逗号分隔列表,但在括号内排除逗号

Java Regex - 拆分逗号分隔列表但排除方括号内的逗号

用于验证数字逗号分隔值的 Java 正则表达式

使用正则表达式匹配多个逗号分隔的单词