在Python中捕获重复模式
我正在尝试为Python日志格式化程序实现某种类似标记的行为 让我们以这个字符串为例:在Python中捕获重复模式,python,regex,Python,Regex,我正在尝试为Python日志格式化程序实现某种类似标记的行为 让我们以这个字符串为例: **这是一个警告**:病毒管理器失败 几个正则表达式之后,字符串失去了类似markdown的语法,并被转换为bash代码: \033[33m\033[1M这是一个警告\033[0m:病毒管理器\033[4M失败\033[0m\033[0m 但这应该压缩到 \033[33;1M这是一个警告\033[0m:病毒管理器\033[4M失败\033[0m 除了许多其他无效的解决方案外,我还尝试了以下方法: (\\033
**这是一个警告**:病毒管理器失败
几个正则表达式之后,字符串失去了类似markdown的语法,并被转换为bash代码:
\033[33m\033[1M这是一个警告\033[0m:病毒管理器\033[4M失败\033[0m\033[0m
但这应该压缩到
\033[33;1M这是一个警告\033[0m:病毒管理器\033[4M失败\033[0m
除了许多其他无效的解决方案外,我还尝试了以下方法:
(\\033\[([\d]+)m{2,}
=>捕获:\033[33m\033[1m
带g1'\033[1m'和g2'1',\033[0m
带g1'\033[0m'和g2'0'
(\\033\[([\d]+)m)+
很多结果,不正常
(?:(\\033\[([\d]+)m)+
许多结果,尽管如果我理解正确,这是重复模式的推荐方法,但不正常
和其他
我的目标是取得以下成果:
输入
\033[33m\033[1M这是一个警告\033[0m:病毒管理器\033[4M失败\033[0m\033[0m
输出
匹配1
033[33m\033[1m
第1组:33
第2组:1
第二场比赛
033[0m\033[0m
第1组:0
第2组:0
换句话说,捕获那些“重复的”不仅仅是那些,所以我可以将它们与regex sub融合。这对于您在这里描述的情况非常简单;只需从左到右写出您想要匹配和捕获的内容。重复捕获块在这里对您没有帮助,因为结果只会返回最近捕获的值
\\033\[(\d+)m\\033\[(\d+)m
要修改的字符串中的模式还没有从问题中弄清楚。例如,
033
是固定的还是可能是025
甚至是25
?我在使用正则表达式时做了一些假设
r" ^(\\0(\d+)\[\2)[a-z]\\0\2\[(\d[a-z].+)
为了获得两个要合并的捕获组,它们之间用分号分隔。我试图在下面阐明我的假设,部分是为了帮助OP修改此正则表达式以满足其他要求
正则表达式执行以下操作:
^ # match beginning of line
( # begin cap grp 1
\\0 # match '\0'
(\d+) # match 1+ digits in cap grp 2
\[ # match '['
\2 # match contents of cap grp 2
) # end cap grp 1
[a-z] # match a lc letter
\\0 # match '\0'
\2 # match contents of cap grp 2
\[ # match '['
(\d[a-z].+) # match a digit, then lc letter then 1+ chars to the
# end of the line in cap grp 3
如您所见,在组1中捕获的字符串部分是
\033[33
我假设这个字符串现在是033
的部分必须是两个或更多以零开头的数字,并且数字字符串的第二次出现由零后面的相同数字组成。这是通过捕获“0”后面的数字来完成的(33
)在捕获组2中,然后使用反向引用\2
字符串的下一部分将被替换,因此不会被捕获:
m\\033[
我假设m
必须是一个小写字母(或者应该是一个文本m
?),反斜杠、零和必需数字以及以下数字必须再次与捕获组2的内容匹配
字符串的其余部分
1mThis is a warning\033[0m: Virus manager \033[4mfailed\033[0m\033[0m
是在捕获组3中捕获的。在这里,我假设它以一个数字开头(可能应该是\d+
),后跟一个小写字母,不必与前面匹配的小写字母相同(尽管可以用另一个捕获组强制执行)。此时,我将该行的其余部分与+
匹配,并放弃了该部分字符串中的匹配模式
或者,一个可能只有两个捕获组,捕获组现在是2,变成1,#2是字符串中要用分号替换的部分。您希望连续匹配重复的
\033[\d+m
文本块,并用分号连接[
后面的数字
你可以用
re.sub(r'(?:\\033\[\d+m){2,}', lambda m: r'\033['+";".join(set(re.findall(r"\[(\d+)", m.group())))+'m', text)
见
(?:\\033\[\d+m){2,}
模式将匹配两个或多个\033[
+一个或多个数字+m
文本块,然后,匹配将传递到lambda表达式,其中输出为:1)\033[
,2)使用re.findall(r)\[(\d+)提取的[/code>之后的所有数字,m.group())
并用集消除重复,然后3)m
有很多不必要的信息,你能发布一个示例输入和预期的输出吗?它在末尾…输入:\033[33;1这是一个警告\033[0m:Virus manager\033[4mfiled\033[0m输出读取消息的结尾表达式创建的匹配组数始终是一个设定值。例如,(…)+
将只生成一个匹配组。这不是100%清楚:规则是什么?您是否有\033[33m\033[1m\033[22m
?如果是,预期的输出是什么?请尝试re.sub(r'(?:\\033\[\d+m{2,}',lambda m:r'\033['+“;”.join(set(re.findall(r“\[(\d+),m.group()))+'m',text)
谢谢,但这只对两个连续的,而不是随机的N个连续的序列有效。我的观点是,这样做不是用一个表达式和重复的捕获组。通常使用一个表达式来获取整个序列,一秒钟(或字符串函数)从中获取一个数字列表和一些处理值的逻辑——如Wiktor Stribiżew的回答。感谢您的详细解释!我将尽快测试并返回结果!