如何使用正则表达式匹配类似CSV的字符串中的数字和数字范围?

时间:2016-05-31 21:03:11

标签: c# .net regex

通常,我喜欢正则表达式的挑战,甚至更好 - 解决它们 但似乎我有一个我无法弄清楚的案例。

我有一串用CSV格式分隔的值,它们看起来像这样: 123-234;FOO-456;45-67;FOO-FOO;890;FOO-123;11-22;123;123;44-55;098-567;890;123-FOO;

在这一行中,我希望匹配所有整数和整数范围,以便稍后提取它们。可能只有单个值(没有分号)。

经过大量的搜索,我设法写了这个表达式:
(?:^|;)(?<range>\d+-\d+)(?:$|;)|(?:^|;)(?<integer>\d+)(?:$|;)

我正在使用的测试字符串:

  1. 123
  2. 123-234;FOO-456;45-67;FOO-FOO;890;FOO-123;11-22;123;123;44-55;098-567;890;123-FOO;
  3. 123-456
  4. 123-FOO
  5. FOO-123
  6. FOO-FOO
  7. 第1行和第3行正确匹配,第4,5行不是 在第2行中,只有一个值正确匹配。

    以下是regex101.com的链接,说明了它:https://regex101.com/r/zA7uI9/5

    我还需要分别选择整数和范围(在不同的组中)。

      

    注意:我找到了一个可以帮助我并尝试答案的问题(通过调整)但它没有用。
      Regular expression for matching numbers and ranges of numbers

    你对我遗失的东西有什么想法吗?

    将“使用”此正则表达式的语言是C#,但我不知道它是否对我的问题有用。

    barlop

    添加了

    以下是当前正则表达式给出的匹配,如regex101.com链接所示

    以及他123-234;FOO-456;45-67;FOO-FOO;890;FOO-123;11-22;123;123;44-55;098-567;89

    的测试字符串
    123-234
    45-67
    890
    11-22
    123
    098-567
    

    所以他的正则表达式似乎错过了123中的一个,44-45和最后的89.

3 个答案:

答案 0 :(得分:6)

C#CSV String Parsing

使用内置的CSV解析器并分别检查每个字段:

using Microsoft.VisualBasic.FileIO;
....
var str = "123-234;FOO-456;45-67;FOO-FOO;890;FOO-123;11-22;123;123;44-55;098-567;890;123-FOO;";
var csv_parser = new TextFieldParser(new StringReader(str));
csv_parser.HasFieldsEnclosedInQuotes = false;   // Fields are not enclosed with quotes
csv_parser.SetDelimiters(";");                  // Setting delimiter
string[] fields;
var range_fields = new List<string>();
var integer_fields = new List<string>();
while (!csv_parser.EndOfData)
{
    fields = csv_parser.ReadFields();
    foreach (var field in fields)
    {
        if (!string.IsNullOrWhiteSpace(field) && field.All(x => Char.IsDigit(x)))
        {
            integer_fields.Add(field);
            Console.WriteLine(string.Format("Intger field: {0}", field));
        }
        else if (!string.IsNullOrWhiteSpace(field) && Regex.IsMatch(field, @"\d+-\d+"))
        {
             range_fields.Add(field);
             Console.WriteLine(string.Format("Range field: {0}", field));
        }
    }
}
csv_parser.Close();

结果是:

Range field: 123-234
Range field: 45-67
Intger field: 890
Range field: 11-22
Intger field: 123
Intger field: 123
Range field: 44-55
Range field: 098-567
Intger field: 890

修复正则表达式方法

你的正则表达式失败的原因是你实际上消费非捕获组的分隔符(即(?:^|;)(?:$|;)仍匹配文本,该文本被追加匹配值,正则表达式索引前进到;,字符串的开始/结束后的位置。

您需要使用的是lookarounds。它们不消耗文本,只是检查是否可以在当前位置之前或之后找到与环绕模式匹配的文本。因此,您有机会获得重叠匹配,并且这是场景非常方便的场景之一。

(?<=^|;)((?<range>\d+-\d+)|(?<integer>\d+))(?=$|;)

regex demo for a .NET regex at a .NET regex syntax supporting RegexStorm

一个很好的图表:

enter image description here

请注意RegexOptions.ExplicitCapture flag的使用:这样,我们避免使用编号(即未命名)捕获组捕获子匹配,​​只获取命名捕获(正是我们需要的)。

C# demo

var s = "123-234;FOO-456;45-67;FOO-FOO;890;FOO-123;11-22;123;123;44-55;098-567;890;123-FOO;";
var rx = new Regex(@"(?<=^|;)((?<range>\d+-\d+)|(?<integer>\d+))(?=$|;)", RegexOptions.ExplicitCapture);
var result = rx.Matches(s)
        .Cast<Match>()
        .Select(x => x.Groups["range"].Success ? 
            x.Groups["range"].Value : x.Groups["integer"].Value
        ).ToList();
foreach (var x in result)
    Console.WriteLine(x);

答案 1 :(得分:2)

我无法轻易地在regex101中看到捕获组,因此该部分可能需要一些调整,但这会使所有匹配正确,并且捕获。希望有人会发布一个改进的答案,但与此同时。

(^\d+(?=;|$))|((?<=;)\d+$)|(?<=;)\d+(?=;)|\d+-\d+

图片,如由ro yo添加的图片

Regular expression visualization

enter image description here

逻辑是,

匹配(^\d+(?=;|$))((?<=;)\d+$)(?<=;)\d+(?=;)\d+-\d+

即。例如一开始(或单独)123,结尾123,中间123,或任何地方。

我无法让regex101.com列出匹配项,但正则表达式正常工作

C:\blah>echo 123-234;FOO-456;45-67;FOO-FOO;890;FOO-123;11-22;123;123;44-55;098-567;89| grep -oP "(^\d+(?=;))|((?<=;)\d+$)|(?<=;)\d+(?=;)|\d+-\d+"

123-234
45-67
890
11-22
123
123
44-55
098-567
89

答案 2 :(得分:1)

描述

(?<=;|^)[0-9]+(?:-[0-9]+|(?=;|$))

Regular expression visualization

此正则表达式将执行以下操作:

  • 匹配半冒号分隔值
  • 从值中提取123等单个整数或123-456等整数范围

实施例

现场演示

https://regex101.com/r/oL1cN2/2

示例文字

123
123-234;FOO-456;45-67;FOO-FOO;890;FOO-123;11-22;123;123;44-55;098-567;890;123-FOO;
123-456
123-FOO
FOO-123
FOO-FOO

样本匹配

123
123-234
45-67
890
11-22
123
123
44-55
098-567
890
123-456