为啥我的 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 修改的输出(在正确的轨道上,但还没有完全实现)
@"(?<Date>\d4-\d2-\d2\s1\d2:\d2:\d2(?:\s\w\w)?)(?<Delim>\s-\s)(?<Text>([\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 Groups
Name
和Value
。命名组后,无需按索引访问。
编辑 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'
。我不明白 - - 财产在那里
明确一点:你的正则表达式的 (?<Text>(?:[\s\S](?!\d4))*)
部分解决了我的问题的核心
解决了group.name
问题。需要将我的目标框架从 4.6.1 升级到 4.7.1
将目标框架更改为 4.7.1 也导致许多不需要的组消失。通过更改 looks forward
来查找整个日期,其余的都消失了:@"(?<Date>\d4-\d2-\d2\s1\d2:\d2:\d2(?:\s\w\w)?)(?<Delim>\s1-\s1)(?<Text>(?:[\s\S](?!\d4-\d2-\d2\s1\d2:\d2:\d2))*)";
以上是关于为啥我的 reg ex 不捕获第二行和后续行?的主要内容,如果未能解决你的问题,请参考以下文章
excel中怎么将一列中的第一行和最后一行互换,第二行和倒数第二行互换,依次类推