为啥我的 reg ex 不捕获第二行和后续行?

Posted

技术标签:

【中文标题】为啥我的 reg ex 不捕获第二行和后续行?【英文标题】:Why does my reg ex not capture 2nd and subsequent lines?为什么我的 reg ex 不捕获第二行和后续行? 【发布时间】:2019-04-01 14:55:10 【问题描述】:

更新

我尝试将RegexOptions.Singleline 添加到我的regex 选项中。它的工作原理是它捕获了以前未捕获的行,但它将整个文本文件放入第一个匹配项中,而不是根据需要在每个日期创建一个匹配项。

更新结束

更新 #2

在使用 Poul Bak 的修改时添加了显示匹配和组的新输出。请参阅下面标题为Poul Bak 修改的输出

的屏幕截图

更新 #2 结束

最终更新

将目标框架从 4.6.1 更新到 4.7.1 并稍微调整 Poul Bak 的 reg ex 解决了所有问题。请参阅下面 Poul Bak 的回答

最终更新结束

原问题:背景

我有以下文本文件test_text.txt

2018-10-16 12:00:01 - Error 1<CR><LF>
   Error 1 text line 1<CR><LF>
   Error 1 text line 2<CR><LF>
2018-10-16 12:00:02 AM - Error 2<CR><LF>
   Error 2 text line 1<CR><LF>
   Error 2 text line 2<CR><LF>
   Error 2 text line 3<CR><LF>
   Error 2 text line 4<CR><LF>
2018-10-16 12:00:03 PM - Error 3

目标

我的目标是让每个匹配项包含 3 个named 组:日期、分隔符和文本,如下所示。

注意:撇号仅用于表示匹配文本的限制。

我希望看到的比赛:

Match 1: '2018-10-16 12:00:01 - Error 1<CR><LF>'
   Date group = '2018-10-16 12:00:01'
   Delim group = ' - '
   Text group = 'Error 1<CR><LF>Error 1 text line 1<CR><LF>Error 1 text line 2<CR><LF>'

Match 2: '2018-10-16 12:00:02 AM - Error 2<CR><LF>'
   Date group = '2018-10-16 12:00:02 AM'
   Delim group = ' - '
   Text group = 'Error 2 text line 1<CR><LF>Error 2 text line 2<CR><LF>Error 2 text line 3<CR><LF>Error 2 text line 4<CR><LF>'

Match 3: `2018-10-16 12:00:03 PM - Error 3`
   Date group = '2018-10-16 12:00:03 PM'
   Delim group = ' - '
   Text group = 'Error 3'

问题

我的正则表达式在第二行和后续文本行中不起作用(例如,“错误 1 ​​文本行 1”、“错误 2 文本行 1”)没有被捕获。我希望它们会被捕获,因为我使用的是 Multiline 选项。

如何修改我的正则表达式以捕获第二行和后续文本行?

当前代码

using System;
using System.Text.RegularExpressions;

namespace ConsoleApp_RegEx

    class Program
    
        static void Main(string[] args)
        

            string text = System.IO.File.ReadAllText(@"C:\Users\bill\Desktop\test_text.txt");
            string pattern = @"(?<Date>\d4-\d2-\d2\s1\d2:\d2:\d2.*)(?<Delim>\s-\s)(?<Text>.*\n|.*)";

            RegexOptions regexOptions = (RegexOptions.IgnoreCase | RegexOptions.Multiline | RegexOptions.CultureInvariant | RegexOptions.IgnorePatternWhitespace | RegexOptions.Compiled);
            Regex rx = new Regex(pattern, regexOptions);
            MatchCollection ms = rx.Matches(text);

            // Find matches.
            MatchCollection matches = rx.Matches(text);

            Console.WriteLine("Input Text\n--------------------\n0\n--------------------\n", text);

            // Report the number of matches found.
            Console.WriteLine("Output (0 matches found)\n--------------------\n", matches.Count);

            int m = 1;

            // Report on each match.
            foreach (Match match in matches)
            
                Console.WriteLine("Match #0: ", m++, match.Value);

                int g = 1;
                GroupCollection groups = match.Groups;

                foreach (Group group in groups)
                
                    Console.WriteLine("   Group #0 1", g++, group.Value);
                

                Console.WriteLine();
            

            Console.Read();
        
    

电流输出

Poul Bak 修改的输出(在正确的轨道上,但还没有完全实现)

@"(?&lt;Date&gt;\d4-\d2-\d2\s1\d2:\d2:\d2(?:\s\w\w)?)(?&lt;Delim&gt;\s-\s)(?&lt;Text&gt;([\s\S](?!\d4))*)"

【问题讨论】:

【参考方案1】:

您可以使用以下修改自您的正则表达式:

@"(?<Date>\d4-\d2-\d2\s1\d2:\d2:\d2(?:\s\w\w)?)(?<Delim>\s-\s)(?<Text>([\s\S](?!\d4))*)"

我更改了'Date' 组,使其接受'AM''PM'(否则它只会匹配第一个)。

然后我更改了'Text' 组,因此它匹配任意数量的任意字符(包括换行符),直到它looks forward 并找到一个新日期。

编辑

我不明白,当你说'AM''PM' 不匹配时,它们是'Date' 组的一部分。我假设您希望他们成为 'Delim' 组的一部分,因此我已将支票移至该组。

我还将一个组更改为非捕获组。

新的正则表达式:

 @"(?<Date>\d4-\d2-\d2\s1\d2:\d2:\d2)(?<Delim>(?:\s\w\w)?\s-\s)(?<Text>(?:[\s\S](?!\d4))*)"

顺便说一句:您应该更改检查组的代码,如下所示:

        foreach (Group group in groups)
        
            Console.WriteLine("   Group #0 1", group.Name, group.Value);
        

然后你会看到你的named GroupsNameValue。命名组后,无需按索引访问。

编辑 2:

关于'group.Name':我误用了'Group'(大写),应该是:'group.Name'。

这就是正则表达式现在的样子:

@"(?<Date>\d4-\d2-\d2\s1\d2:\d2:\d2(?:\s\w\w)?)(?<Delim>\s-\s)(?<Text>(?:[\s\S](?!\d4))*)"

我建议你设置 'RegexOptions.ExplicitCapture' 标志,然后你只会得到命名组。

【讨论】:

感谢您的努力。您的正则表达式肯定会捕获第二行和后续行,但日期后面的文本可以是“ - ”、“ AM - ”或“ PM - ”,并且您的正则表达式会丢失该部分,此外,您的正则表达式会创建许多不需要的组。请参阅我的答案中标题为 Poul Bak 的修改输出 的屏幕截图。我正在检查你的正则表达式,看看我需要保留哪一部分才能获得第二行和后续行 我的错!对于 AM、PM 或两者都不是,您的原始正则表达式是正确的。我的眼睛只是错过了它。但是,问题仍然存在:您的正则表达式创建了许多不需要的组。将标记为 Poul Bak 的修改输出 的输出与标记为 我期望看到的匹配项: 的输出进行比较。另外:当我打开调试器时,我在 group 对象中看到了 Name 属性,但是当我尝试添加 'Console.WriteLine(" Group #0 1", group.Name, group .Value);',编译器说'Group does not contain a definition for 'Name'。我不明白 - - 财产在那里 明确一点:你的正则表达式的 (?&lt;Text&gt;(?:[\s\S](?!\d4))*) 部分解决了我的问题的核心 解决了group.name 问题。需要将我的目标框架从 4.6.1 升级到 4.7.1 将目标框架更改为 4.7.1 也导致许多不需要的组消失。通过更改 looks forward 来查找整个日期,其余的都消失了:@"(?&lt;Date&gt;\d4-\d2-\d2\s1\d2:\d2:\d2(?:\s\w\w)?)(?&lt;Delim&gt;\s1-\s1)(?&lt;Text&gt;(?:[\s\S](?!\d4-\d2-\d2\s1\d2:\d2:\d2))*)";

以上是关于为啥我的 reg ex 不捕获第二行和后续行?的主要内容,如果未能解决你的问题,请参考以下文章

excel中怎么将一列中的第一行和最后一行互换,第二行和倒数第二行互换,依次类推

使用 CSS 从表格的第二行替换行颜色

在排除某些行的矩阵的列中查找最大元素

javascript,为啥在播放视频时第二行无法从第一行替换?

word打字时换行之后,第二行首字无法用空格

MySQL如何锁定一行及如何分析行锁定