正则表达式/ Python - 为什么在这种情况下捕获非捕获组?

时间:2015-08-28 08:19:11

标签: python regex

此原始数据数组的每个元素都由regex

解析
['\r\n\t\t\t\t\t\t', 
 'Monday, Tuesday, Wednesday, Thursday, Friday, Saturday:', 
 ' 12:00 pm to 03:30 pm & 07:00 pm to 12:00 am\t\t\t\t\t',      
 '\r\n\t\t\t\t\t\t', 
 'Sunday:', 
 ' 12:00 pm to 03:30 pm & 07:00 pm to 12:30 am\t\t\t\t\t']

这是我的正则表达式(\\r|\\n|\\t)|(?:\D)(\:)

https://regex101.com/r/fV7wI2/1

enter image description here

请注意,我尝试匹配星期六之后的:,而不是时间格式中的:,例如12:00

虽然上面的图像正确地分类捕获/非捕获组

运行re.sub("(\\r|\\n|\\t)|(?:\D)(\:)",'',"Monday, Tuesday, Wednesday, Thursday, Friday, Saturday:")

返回

'Monday, Tuesday, Wednesday, Thursday, Friday, Saturda'(星期六之后错过'y')

而不是

'Monday, Tuesday, Wednesday, Thursday, Friday, Saturday'

为什么会这样?

3 个答案:

答案 0 :(得分:2)

如果要检查子字符串是否存在,则需要使用后视而不是非捕获组,但是要将其从匹配项中排除:

import re
s = "Monday, Tuesday, Wednesday, Thursday, Friday, Saturday:"
print(re.sub(r"[\r\n\t]|(?<!\d):",'',s))
#                         ^^^^^^^ 
# Result: Monday, Tuesday, Wednesday, Thursday, Friday, Saturday

请参阅IDEONE demo

此处,(?<!\d)仅检查冒号前面的字符是否不是数字。

此外,更改涉及额外开销,最好使用字符类[\r\n\t],并且您不需要任何捕获组(圆括号),因为您根本不使用它们。

另外,请注意正则表达式使用原始字符串文字进行初始化,以避免过度使用。

关于非捕获组否定后卫的一些more details from Python Regular Expression Syntax

  

(?<!...)
    - 如果字符串中的当前位置前面没有...的匹配项,则匹配。这被称为负面的后观断言。与正向lookbehind断言类似,包含的模式必须仅匹配某些固定长度的字符串,并且不应包含组引用。以负向lookbehind断言开头的模式可能在被搜索字符串的开头匹配。

     

(?:...)
   - 常规括号的非捕获版本。匹配括号内的正则表达式,但在执行匹配后或在模式中稍后引用时,无法检索组匹配的子字符串。

后视是零宽度断言(=表达式返回 true false 而不在字符串中进一步移动索引) ,在这种情况下,你想要检查而不是匹配,它们正是你所需要的。非捕获组将消耗部分字符串,因此将成为匹配的一部分。

答案 1 :(得分:1)

\D为非数字。saturday ynon digit,因此会被删除。

使用

print re.sub("(\\r|\\n|\\t)|(?<=\D):",'',"Monday, Tuesday, Wednesday, Thursday, Friday, Saturday:")

使用lookahead可确保您在: /

之前不删除多余的字符

答案 2 :(得分:1)

我认为您误解了(?:\D)不会在Regex中将其作为一个字母考虑,实际上它是错误的,它只是没有将\D捕获到变量中$1。每次使用(...)时,您必须意识到(...)中的任何模式都会被捕获到变量中$1$2,...中的变量。

解决这个问题的最佳方法是使用正面/负面预测作为@vks和@stribizhev的答案,因为外观只是一个不消耗任何字母的断言,这就是为什么我们称之为&# 34;零宽度断言&#34;