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

Nii*_*aku 6 .net c# 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

第1行和第3行正确匹配,第4,5行不正确.
在第2行中,只有一个值正确匹配.

下面是regex101.com一个链接,说明它:https://regex101.com/r/zA7uI9/5

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

注意:我发现了一个可以帮助我并尝试答案的问题(通过调整),但它没有用.
用于匹配数字和数字范围的正则表达式

你知道我错过了什么吗?

将"使用"此正则表达式的语言是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
Run Code Online (Sandbox Code Playgroud)

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

Wik*_*żew 6

C#CSV字符串解析

使用内置的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();
Run Code Online (Sandbox Code Playgroud)

结果是:

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
Run Code Online (Sandbox Code Playgroud)

修复正则表达式方法

原因您正则表达式失败是你实际消耗的符与非捕获组(即(?:^|;)(?:$|;)仍然匹配的文本,该文本被附加到匹配值,和正则表达式指数是先进的后的位置;,开始/结束的字符串).

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

(?<=^|;)((?<range>\d+-\d+)|(?<integer>\d+))(?=$|;)
Run Code Online (Sandbox Code Playgroud)

支持RegexStorm的.NET正则表达式语法的.NET正则表达式正则表达式演示

一个很好的图表:

在此输入图像描述

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

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);
Run Code Online (Sandbox Code Playgroud)