正则表达式将字符串中的日期与where子句

时间:2019-04-01 08:49:16

标签: c# .net regex

我需要从下面的示例文本中获取日期字符串,即 2019-01-22 15:36:141,023 ,仅当该行包含 Correct 而不是 > Test12 字。因此,理想情况下,我应该在下面的字符串中得到两个匹配项(第3行和第5行)。

第1行:2019-01-22 15:36:141,043:[Test] [123]信息-测试:正确的Test12 ping

第2行:2019年1月22日15:36:141,029:[Test] [124323]信息-测试:Test12 ping错误

第3行:2019-01-22 15:36:141,023:[Test] [12554363]信息-测试:正确的测试ping

第4行:2019年1月22日15:36:141,123:[Test] [6761213]信息-测试:Test12 ping错误

第5行:2019年1月22日15:36:141,093:[Test] [46543123]信息-测试:无效的测试ping

第6行:2019年1月22日15:36:141,890:[Test] [887]信息-测试:正确的测试ping

我可以使用(?\ d {4}-\ d {2}-\ d {2} \ s \ d {2}:\ d {2}:\ d {2 }(?:,\ d {3} \ b)?),但不确定如何包括其他条件。有线索吗?

3 个答案:

答案 0 :(得分:4)

无需增加正则表达式的复杂性,您可以遍历文件中的行并使用常规字符串方法对Test12Correct进行检查:

var results = new List<string>();
using (var sr = new StreamReader(filepath, true)) 
{
    var line = "";
    while ((line=sr.ReadLine()) != null)
    {
        if (line.Contains("Correct") && !line.Contains("Test12")) 
        {
            var res = Regex.Match(line, @"\d{4}-\d{2}-\d{2}\s\d{2}:\d{2}:\d{2,}(?:,\d{3}\b)?");
            if (res.Success)
            {
                results.Add(res.Value);
            }
        }
    }
}

使用正则表达式,我要在要检查的日期之后

\d{4}-\d{2}-\d{2}\s\d{2}:\d{2}:\d{2,}(?:,\d{3}\b)?(?!.*Test12)(?=.*Correct)
                                                  ^^^^^^^^^^^^^^^^^^^^^^^^^

请参见regex demo

在这里,(?!.*Test12)(?=.*Correct)是先行方式,可确保1)没有Test12,并且2)在除换行符以外的任意0+个字符之后,尽可能多地包含一个子字符串Correct当前位置的右侧(即日期之后)。

如果这些单词可能出现在字符串中的任何地方,则可以使用

(?m)\d{4}-\d{2}-\d{2}\s\d{2}:\d{2}:\d{2,}(?:,\d{3}\b)?(?=.*\r?$(?<!Test12.*)(?<=Correct.*))
                                                      ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^

请参见this regex demo

在这里,(?m)选项将RegexOptions.Multiline设置为 true ,以便将$解析为行锚的结尾,而将{{ 1}}正向超前执行以下检查:它要求在行尾最多有0+个字符,然后在行末,使用lookbehinds执行两项检查:负向后{{1 }}确保一行上没有(?=.*\r?$(?<!Test12.*)(?<=Correct.*)) ,并且(?<!Test12.*)后的正向外观确保任何地方都没有Test12子字符串 在线。

在多行模式下,(?<=Correct.*)Correct之前不匹配,这是一个令人烦恼的事实,因此需要\r?之前的$可选CR。

答案 1 :(得分:2)

我认为您的意思是匹配第3行和第6行,因为第5行不包含Correct

要不包含“ Test12”,可以使用负前瞻。要在以后匹配“正确”,可以在模式中匹配它,并使用单词边界\b来防止它成为较大单词的一部分。

您的模式可能如下:

^(?!.*\bTest12\b).*?(\d{4}-\d{2}-\d{2}\s\d{2}:\d{2}:\d{2,}(?:,\d{3}\b)?).*\bCorrect\b.*$

这将匹配:

  • ^字符串的开头
  • (?!.*\bTest12\b)断言以下内容不包含Test12
  • .*?匹配任何不适合char的字符
  • (\d{4}-\d{2}-\d{2}\s\d{2}:\d{2}:\d{2,}(?:,\d{3}\b)?)分组捕获日期,例如图案
  • .*匹配任何char 0次以上
  • \bCorrect\b匹配正确
  • .*匹配任何char 0次以上
  • $字符串的结尾

Regex demo | C# demo

注意

(?:,\d{3}\b)?的这个部分也应该与逗号之前的数字相匹配,例如(?:\d,\d{3}\b)?,查看示例数据吗?

答案 2 :(得分:0)

这是不使用正则表达式的一种方法。日期看起来不正确。我认为逗号的位置错误,因此我将其修复。

            DateTime today = DateTime.Parse("2019-01-22 15:36:14");
            string input =
                "2019-01-22 15:36:14,1023: [Test][123] INFORMATION - Testing: Correct Test12 ping\n" +
                "2019-01-22 15:36:14,1023: [Test][124323] INFORMATION - Testing: Wrong Test12 ping\n" +
                "2019-01-22 15:36:14,1023: [Test][12554363] INFORMATION - Testing: Correct Test ping\n" +
                "2019-01-22 15:36:14,1023: [Test][6761213] INFORMATION - Testing: Wrong Test12 ping\n" +
                "2019-01-22 15:36:14,1023: [Test][46543123] INFORMATION - Testing: Invalid Test ping\n" +
                "2019-01-22 15:36:14,1023: [Test][887] INFORMATION - Testing: Correct Test ping";

            StringReader reader = new StringReader(input);
            string line = "";

            while ((line = reader.ReadLine()) != null)
            {
                string[] splitDate = line.Split(new string[] { ": [Test]" }, StringSplitOptions.None);
                DateTime date = DateTime.ParseExact(splitDate[0].Replace(",","."), "yyyy-MM-dd HH:mm:ss.FFFF", System.Globalization.CultureInfo.InvariantCulture);
                string[] splitTest = splitDate[1].Split(new char[] { ':' });

                if ((date.Date == today.Date) && splitTest[1].Contains("Correct") && !splitTest[1].Contains("Test12"))
                {
                    Console.WriteLine(line);
                }
            }
            Console.ReadLine();