我正在尝试用重复的值匹配多行。如果有多个匹配项,我的脚本将继续。我一直在浏览反向引用文档,但似乎无法满足我的情况。
这个想法是查询一个包含时间戳和动作的日志文件。我想将日志文件中包含重复时间戳的任何行与包含在行中的“开始”字符串进行匹配。
使用此模式:
^(\b\d+)-(\d{2})-(\d{2}) (\d+):(\d{2})(?=\b[\s\S]*Starting\b)(?=[\s\S]*\b\1\b)
我希望匹配前两行,只是因为时间戳完全相同。
2019-10-31 05:49:52.416 +10:00 [1] - Starting
2019-10-31 05:49:53.416 +10:00 [1] - Starting
2019-10-31 06:53:58.416 +10:00 [1] - Starting
目前,它仅捕获第一行(1个匹配项)。如何获取它以匹配多行中的重复值?
编辑:
为澄清起见,我的模式正在寻找YYYY-MM-DD HH:MM的重复值。
答案 0 :(得分:1)
(?<log>(?<ymdhm>\d{4}-\d{2}-\d{2} \d{2}:\d{2}).*?(?<flag>Starting)$)\n\k<ymdhm>.*?\k<flag>
[更新]
好吧,我更新了正则表达式,这并不容易。
以下是说明:
组“ log”根据您的基本规则匹配一行。它分为几个部分:
(?<ymdhm>\d{4}-\d{2}-\d{2} \d{2}:\d{2})
“ ymdhm” YY-MM-DD HH:MM,这是为以后的匹配而导入的,因为您需要注意直到数分钟的时间数字,所以下一个合格的行必须具有完全相同的模式。 (?<flag>Starting)$
“标志”是导入模式,这就是您要查找的内容,即“标志”。 .*?
在它们之间的中间是您不太在乎的字符。 然后,它必须有另一行\n
。此处,regexp使用标志gm
。如果没有\n
,它将停止检查以下行。
\k<ymdhm>
意味着应用与最后一组“ ymdhm”相同的模式,这意味着下一个日志的时间应具有相同的数字。 Explanation代表\k
。
\k<flag>
与上一个匹配的标志模式匹配。 答案 1 :(得分:1)
(?:^|\n)(\d{4}(?:-\d{2}){2} (?:\d{2}:){2})\d{2}\.\d{3}( [+-]\d{2}:\d{2} )\[\d+\]( - Starting)[^\n]*(\n\1\d{2}\.\d{3}\2\[\d+\]\3[^\n]*)+
注意:
替换所有\s+
即可)我不同意@ggorlen的评估,对于需要这种表达能力的问题,正则表达式实际上是您可以做的最快的事情。
但是,如果您需要匹配不连续的“开始”行,但是则可以保证按顺序排列(基本上对于所有日志来说都是这样,同一分钟的“开始”行和非“开始”行都将彼此相邻),我们可以对此进行调整并仍然保持合理高效:
(?:^|\n)(\d{4}(?:-\d{2}){2} (?:\d{2}:){2})\d{2}\.\d{3}( [+-]\d{2}:\d{2} )\[\d+\]( - Starting)[^\n]*(?:\n\1\d{2}\.\d{3}\2\[\d+\][^\n]*)*\n\1\d{2}\.\d{3}\2\[\d+\]\3[^\n]*
Have a play,以确保它可以满足您的需求
具有与b̲l̲o̲c̲k̲s̲匹配的相同警告,因此,匹配“起始”行之间的非起始行仍将匹配。
为了提高效率以使每行单独匹配,我们可以对这两个半部使用超前/后退。
我们需要复制正则表达式以捕获块的不同末端。
Some browsers wont even let you do crazy stuff like this,即使Chrome不能使所有在线测试人员都let me give you a breakdown of the resulting regex
(?:^|\n)(\d{4}(?:-\d{2}){2} (?:\d{2}:){2})\d{2}\.\d{3}( [+-]\d{2}:\d{2} )\[\d+\]( - Starting)[^\n]*(?=(?:\n\1\d{2}\.\d{3}\2\[\d+\][^\n]*)*\n\1\d{2}\.\d{3}\2\[\d+\]\3[^\n]*)|(?<=(?:^|\n)(\d{4}(?:-\d{2}){2} (?:\d{2}:){2})\d{2}\.\d{3}( [+-]\d{2}:\d{2} )\[\d+\]( - Starting)[^\n]*(?:\n\4\d{2}\.\d{3}\5\[\d+\][^\n]*)*)\n\4\d{2}\.\d{3}\5\[\d+\]\6[^\n]*
幸运的是,PowerShell(正如您在评论中提到的那样)仍然可以很好地处理它,但是我敢肯定,对于大型日志文件,PowerShell会停止运行。
(
([regex](
(
'(?:^|\n)(\d{4}(?:-\d{2}){2} (?:\d{2}:){2})\d{2}\.\d{3}( [+-]\d{2}:\d{2} )\[\d+\]( - Starting)[^\n]*(?=(?:\n\1\d{2}\.\d{3}\2\[\d+\][^\n]*)*\n\1\d{2}\.\d{3}\2\[\d+\]\3[^\n]*)',
'(?<=(?:^|\n)(\d{4}(?:-\d{2}){2} (?:\d{2}:){2})\d{2}\.\d{3}( [+-]\d{2}:\d{2} )\[\d+\]( - Starting)[^\n]*(?:\n\4\d{2}\.\d{3}\5\[\d+\][^\n]*)*)\n\4\d{2}\.\d{3}\5\[\d+\]\6[^\n]*'
) -join '|')
).Matches((
'2019-10-31 05:49:52.416 +10:00 [1] - Starting',
'2019-10-31 05:49:53.416 +10:00 [2] - not starting',
'2019-10-31 05:49:53.416 +10:00 [2] - Starting',
'2019-10-31 05:49:53.416 +10:00 [3] - Starting',
'2019-10-31 06:53:58.416 +10:00 [1] - Starting',
'2019-10-31 06:53:58.416 +10:00 [1] - Identical but not "starting"'
) -join "`n")
).Value
答案 2 :(得分:1)
您可以使用backreference来捕获以下所有行中认为相同的时间戳部分,并且还可以在第二次捕获中捕获Starting
的一部分组。
然后,您可以重复匹配以与组1相同的值开始并在行中包含组2的所有行。
^(\d{4}-\d{2}-\d{2} \d{2}:\d{2}).*(\bStarting\b)(?:\R\1.+\2)+
^
行的开头(
捕获第1组
\d{4}-\d{2}-\d{2} \d{2}:\d{2}
与您要捕获的类似时间戳的格式匹配)
关闭群组.+
匹配除换行符1次以上以外的所有字符(
捕获第2组
\bStarting\b
匹配词边界之间的匹配)
关闭群组(?:
非捕获组
\R\1.+\2
匹配Unicode换行符序列,对第1组中捕获的内容的反向引用是除换行符以外的任何字符的1倍以上,对第二组中捕获的内容的反向引用)+
关闭非捕获组并重复1次以上以匹配至少2行