【问题标题】:Regular expressions: extract numbers separated by commas from strings正则表达式:从字符串中提取用逗号分隔的数字
【发布时间】:2013-04-21 10:37:07
【问题描述】:

我需要从这样的字符串中提取用逗号分隔的数字(任意数量的数字和空格):

Expression type:            Answer:
(1, 2,3)                    1,2,3
(1,3,4,5,77)                1,3,4,5,77
( b(2,46,8,4,5, 52)    y)   2,46,8,4,5,52
(a (3, 8,2, 1, 2, 9) x)     3,8,2,1,2,9

【问题讨论】:

  • a) 其中哪些部分是可变的? b) 你试过什么?
  • 变量将是这样的数字:(number ,number,...,number) 括号中的数字可以带有空格。我使用的是简单的拆分技术,但这并不优雅且容易出错

标签: c# .net regex powershell


【解决方案1】:

试试这个模式:

\((?:\s*\d+\s*,?)+\)

例如:

var results = Regex.Matches(input, @"\((?:\s*\d+\s*,?)+\)");
Console.WriteLine(results[0].Value); // (1,2,3)

如果您想将其转换为整数列表,您可以使用 Linq 轻松完成:

var results = Regex.Matches(input, @"\((?:\s*(\d+)\s*,?)+\)")
                   .Cast<Match>()
                   .SelectMany(m => m.Groups.Cast<Group>()).Skip(1)
                   .SelectMany(g => g.Captures.Cast<Capture>())
                   .Select(c => Convert.ToInt32(c.Value));

或者在查询语法中:

var results = 
    from m in Regex.Matches(input, @"\((?:\s*(\d+)\s*,?)+\)").Cast<Match>()
    from g in m.Groups.Cast<Group>().Skip(1)
    from c in g.Captures.Cast<Capture>()
    select Convert.ToInt32(c.Value);

【讨论】:

  • 这将捕获单个数字(带有尾随逗号),而不是整个 (1,2,3)
  • @m.buettner 当然会。 results[0].Value 将是 (1,2,3)
  • 哦,对了。显然,现在还为时过早...尽管(?:\d+,?),您可以使该组不被捕获...我认为这也是一种好习惯。
  • 您的正则表达式将匹配以空格分隔的数字 ((1 2)) 以及带有尾随逗号 ((1,2,)) 但不带有前导逗号 ((,1,2)) 的数字序列。
【解决方案2】:

是您将始终拥有的精确搜索字符串吗?

(number1,number2,numer3) 文本...

编辑:您提供了应该处理它们的新示例:

    string input = "( b(2,46,8,4,5, 52)    y)";
    input = input.Remove(" ","");
    var result = Regex.Matches(input, @"\(([0-9]+,)+[0-9]+\)");
    Console.WriteLine(result[0]);

【讨论】:

  • 确实如此 - 但他的问题没有显示其他情况。我不确定他需要什么
  • 此代码还将匹配以空格分隔的数字,例如(1 2,3),但不会匹配单个数字,例如(1).
【解决方案3】:

看到也可能有空格,这里是一个建议,unrolls the loop(对于较大的输入来说效率更高一些):

@"[(]\d+(?:,\d+)*[)]"

您当然也可以用反斜杠转义括号。我只是想展示一个替代方案,我个人认为它更具可读性。

如果您最终想要获取数字,而不是拆分正则表达式的结果,您可以立即捕获它们:

@"[(](?<numbers>\d+)(?:,(?<numbers>\d+))*[)]"

现在numbers 组将是所有数字的列表(作为字符串)。

我又完全忘记了空格,所以这里是空格(不是捕获的一部分):

@"[(]\s*(?<numbers>\d+)\s*(?:,\s*(?<numbers>\d+)\s*)*[)]"

【讨论】:

  • 虽然我同意它更具可读性,但这并没有考虑到空格。另外我不知道你可以重复使用这样的组名。
  • @p.s.w.g 由于他不想在他的结果中有空格,我会在使用正则表达式之前删除它们。
  • @WhileTrueSleep +1 因为这完全回答了 OP 的问题。但是由于字符串的大小会更小,在匹配后将它们删除会更有效吗?
  • @p.s.w.g 我认为在使用正则表达式搜索之前删除它们会更快。但这是我没有测量的猜测
  • @p.s.w.g 在我的第一句话和我完全忘记空间的模式之间不知何故 o.O ...我会进行编辑。关于组名,这只能在 .NET 中使用,我认为这是引擎最有用的功能之一。
【解决方案4】:

我可能会使用这样的正则表达式:

\((\d+(?:\s*,\s*\d+)*)\)

使用这样的 PowerShell 代码:

$str = @(
    "(1, 2,3)"
  , "(1,3,4,5,77)"
  , "( b(2,46,8,4,5, 52)"
  , "(a (3, 8,2, 1, 2, 9) x)"
  , "(1)"
  , "(1 2, 3)"    # no match (no comma between 1st and 2nd number)
  , "( 1,2,3)"    # no match (leading whitespace before 1st number)
  , "(1,2,3 )"    # no match (trailing whitespace after last number)
  , "(1,2,)"      # no match (trailing comma)
)
$re  = '\((\d+(?:\s*,\s*\d+)*)\)'

$str | ? { $_ -match $re } | % { $matches[1] -replace '\s+', "" }

正则表达式将匹配一个(子)字符串,该字符串以左括号开头,后跟以逗号分隔的数字序列(在逗号之前或之后可以包含任意数量的空格)并以右括号结尾。随后,-replace 指令会删除空格。

如果您不想匹配单个数字 ("(1)"),请将正则表达式更改为:

\((\d+(?:\s*,\s*\d+)+)\)

如果要在左括号之后或右括号之前允许空格,请将正则表达式更改为:

\(\s*(\d+(?:\s*,\s*\d+)*)\s*\)

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2013-04-19
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多