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;
csv_parser.SetDelimiters(";");
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
修正正则表达式的方法
你的正则表达式失败的原因是你实际上使用非捕获组(即(?:^|;)
和(?:$|;)
)来匹配定界符,并将定界符“消耗掉”了。这意味着匹配的文本被附加到匹配值上,而且正则表达式索引会被移动到分号(或字符串开头/结尾)后面的位置。
你需要使用环视语法。它们不会消耗文本,只是检查当前位置之前或之后是否能找到与环视模式匹配的文本。因此,你有机会获取重叠匹配,这是环视非常方便的一种应用场景。
(?<=^|;)((?<range>\d+-\d+)|(?<integer>\d+))(?=$|;)
这是一个支持.NET正则表达式语法的.NET正则表达式演示
下面是一张示意图:
注意使用RegexOptions.ExplicitCapture
标志:这样,我们就避免了使用带编号(即未命名)捕获组获取子匹配,并且只获得命名捕获(正是我们所需要的)。
C#演示:
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);
(?<=^|;)\d+(?:-\d+)?(?=$|;)
。 - Wiktor Stribiżew(?<=^|;)(?:(?<float>\d+-\d+)|(?<int>\d+))(?=$|;)
。 - Wiktor Stribiżew