Regex.Split() 的奇怪行为

4

我尝试使用以下正则表达式来分割文本文件中的数据,但在测试过程中发现了一个奇怪的错误 - 即使是非常简单的文件也会被错误地分割。以下是用于说明这种行为的示例代码:

        const string line = "511525,3122,9,39,2007,9,39,3127,9,39,\" -49,368.11 \",\"-32,724.16\",2,1,\" 2,347.91 \", -   ,\" 2,234.17 \", -   ,2.2,1.143,2,1.24,FALSE,1,2,0,311,511625";
        const string pattern = ",(?=([^\"]*\"[^\"]*\")*[^\"]*$)";

        Console.WriteLine();
        Console.WriteLine("SPLIT");
        var splitted = Regex.Split(line, pattern, RegexOptions.Compiled);
        foreach (var s in splitted)
        {
            Console.WriteLine(s);
        }

        Console.WriteLine();
        Console.WriteLine("REPLACE");
        var replaced = Regex.Replace(line, pattern, "!" , RegexOptions.Compiled);
        Console.WriteLine(replaced);

        Console.WriteLine();
        Console.WriteLine("MATCH");
        var matches = Regex.Matches(line, pattern);
        foreach (Match match in matches)
        {
            Console.WriteLine(match.Index);
        }

因此,正如您所看到的,split方法是唯一会产生意外结果(它在无效位置上拆分!)的方法!MatchesReplace都会给出完全正确的结果。我甚至尝试在RegexBuddy中测试提到的正则表达式,它显示与Regex.Matches相同的匹配项!我是否漏掉了什么,还是Split方法中存在错误?

控制台输出

SPLIT
511525
, -   ," 2,234.17 "
3122
, -   ," 2,234.17 "
9
, -   ," 2,234.17 "
39
, -   ," 2,234.17 "
2007
, -   ," 2,234.17 "
9
, -   ," 2,234.17 "
39
, -   ," 2,234.17 "
3127
, -   ," 2,234.17 "
9
, -   ," 2,234.17 "
39
, -   ," 2,234.17 "
" -49,368.11 "
, -   ," 2,234.17 "
"-32,724.16"
, -   ," 2,234.17 "
2
, -   ," 2,234.17 "
1
, -   ," 2,234.17 "
" 2,347.91 "
 -   ," 2,234.17 "
 -
" 2,234.17 "
" 2,234.17 "
 -
2.2
1.143
2
1.24
FALSE
1
2
0
311
511625

REPLACE
511525!3122!9!39!2007!9!39!3127!9!39!" -49,368.11 "!"-32,724.16"!2!1!" 2,347.91 "! -   !" 2,234.17 "! -   !2.2!1.143!2!1.24!FALSE!1!2!0!311!511625

MATCH
6
11
13
16
21
23
26
31
33
36
51
64
66
68
81
87
100
106
110
116
118
123
129
131
133
135
139

2
你是否阅读了文档中关于捕获括号的说明,特别是多个捕获括号同时存在时的行为? - Damien_The_Unbeliever
@Marnix van Valen,正如我所提到的,我已经使用RegexBuddy检查了正则表达式。 - illegal-immigrant
@Damien_The_Unbeliever,我不确定。你认为这是原因吗? - illegal-immigrant
@Damien_The_Unbeliever 请查看我发布的链接。 - illegal-immigrant
我认为如果列表中的第一个项目是包含逗号的带引号字符串,那么这个正则表达式将无法按照广告宣传的方式工作。 - Damien_The_Unbeliever
显示剩余4条评论
2个回答

2

2
根据微软的回复(添加ExplicitCapture),问题似乎在于捕获组。ExplicitCapture选项将把该捕获组转换为非捕获组。
您也可以通过显式地将该组设置为非捕获组来达到相同的效果:
const string pattern = ",(?=(?:[^\"]*\"[^\"]*\")*[^\"]*$)";

经测试使用LINQPad,似乎可以产生所需的结果。
是否存在捕获组会影响Regex.Split的结果,如文档中所述。
引用块: 如果在Regex.Split表达式中使用捕获括号,则任何已捕获的文本都包含在生成的字符串数组中。例如,在放置在捕获括号内的连字符上将字符串“plum-pear”分割时,添加一个包含连字符的字符串元素以返回数组。

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接