带有嵌套组和点的正则表达式导致古怪的匹配
Regex with nested group and dot causes wacky matching
我无法理解为什么以下正则表达式和文本会产生结果。我在 notepad++ 中使用正则表达式查找函数,没有 Wrap_around 也没有匹配的换行符。正则表达式:
name ="[\w]+\.((?:[\w]*\.?)+)" p
应用于文本时:
name ="data.messageHeader.msg_time_tag.$date" pzb
this is line 2
整个文本最终突出显示,这应该是不可能的,因为正则表达式不应该能够匹配美元符号或 newline/carriage return.
我也尝试过将正则表达式应用于 python 're' 的文本。在这种情况下,我逐行解析了整个文件。最初,python 没有正确匹配带有美元符号的行,但这些行需要几秒钟才能完成,即使它们只有大约 100 个字符。在包含我的示例结构的第四行或第五行,其中以点分隔的单词包含一个“$”,python 冻结,直到我手动停止它。
使用的python代码:
import re
def main():
pattern = re.compile(r"name =\"\w+\.((?:\w+\.?)+)\" p")
with open(r"filepath", "r") as f:
i = 0
for line in f:
match = pattern.search(line)
if (match):
print('<Match: %r, groups=%r>' % (match.group(), match.groups()))
else:
print("line %d nomatch" % (i))
i+=1
match = None
#it = pattern.finditer(f.read())
#for element in it:
#displaymatch(element)
def displaymatch(match):
if match is None:
return None
print('<Match: %r, groups=%r>' % (match.group(), match.groups()))
main()
你能解释一下为什么会这样吗?
在选择文本之前,我在 Notepad++ 中停顿了很长时间,这表明它陷入了无限循环,而选择所有文本只是它在这样的循环中跳出时的默认行为。
现在,由于这部分 (?:[\w]*\.?)
可以折叠成空,并且可以出现一次或多次,我猜它只是重复匹配任何内容,直到找到匹配 $
的内容。
name ="[\w]+\.((?:[\w$]*\.?)+)" p
似乎工作正常。
更新:
这似乎可以解决您的问题:
name ="\w+\.(?:(\w+\.)*\w+)" p
既然你想知道为什么你的模式不起作用,这里是它的细分:
name =" - capture a literal string: `name ="`
\w+ - ... followed by one or more word characters (A-Za-z0-9_)
\. - ... followed by a literal dot
( - start a capturing group (following matches will be captured as a group)
(?: - start a non-capturing group
\w+ - match one or more word characters (A-Za-z0-9_)
\.? - ... optionally followed by a literal dot
)+ - match as many of these non-capturing groups as possible
) - close the group, nothing is captured as there is no capturing pattern in it
" p - followed by a literal string: `" p`
想像这样的字符串:name ="data.messageHeader.msg_time_tag.$date" pzb
。如果你在上面执行上面的模式,你会很容易地捕获你的 name ="data.
部分,这就是乐趣开始的时候 - 不要介意外部组,问题在于内部组和它后面的 +
限定符 -它将匹配第一个 messageHeader.
,然后它会捕获 msg_time_tag.
等等,直到遇到引号字符...但是,由于 $date
不符合内部模式,它会移动回到 messageHeader.
的上一场比赛(回溯)并再次尝试 - 只是遇到同样的问题,并再次回溯......再次......再次......最终关闭引擎并导致非-可预测的行为。
正则表达式引擎将如何选择处理这个取决于实现 - 最合适的方法是引发 infinite/catastrophic 回溯错误(因为尽管有匹配和模式不提供解决方案),但它可能会因什么都不捕获或捕获所有而失败...
底线是 - 如果您编写正确的正则表达式模式,正则表达式引擎将按预期运行。如果没有 - 一切顺利。
正如 Wiktor 所说,正则表达式将导致灾难性的回溯。具体来说,它是可选的周期,在回溯时,将允许正则表达式尝试搜索字符串的指数排列。以下正则表达式通过强制内部单词后跟句点来防止灾难性回溯。
name ="\w+\.((\w+\.)*\w+)" p
我无法理解为什么以下正则表达式和文本会产生结果。我在 notepad++ 中使用正则表达式查找函数,没有 Wrap_around 也没有匹配的换行符。正则表达式:
name ="[\w]+\.((?:[\w]*\.?)+)" p
应用于文本时:
name ="data.messageHeader.msg_time_tag.$date" pzb
this is line 2
整个文本最终突出显示,这应该是不可能的,因为正则表达式不应该能够匹配美元符号或 newline/carriage return.
我也尝试过将正则表达式应用于 python 're' 的文本。在这种情况下,我逐行解析了整个文件。最初,python 没有正确匹配带有美元符号的行,但这些行需要几秒钟才能完成,即使它们只有大约 100 个字符。在包含我的示例结构的第四行或第五行,其中以点分隔的单词包含一个“$”,python 冻结,直到我手动停止它。
使用的python代码:
import re
def main():
pattern = re.compile(r"name =\"\w+\.((?:\w+\.?)+)\" p")
with open(r"filepath", "r") as f:
i = 0
for line in f:
match = pattern.search(line)
if (match):
print('<Match: %r, groups=%r>' % (match.group(), match.groups()))
else:
print("line %d nomatch" % (i))
i+=1
match = None
#it = pattern.finditer(f.read())
#for element in it:
#displaymatch(element)
def displaymatch(match):
if match is None:
return None
print('<Match: %r, groups=%r>' % (match.group(), match.groups()))
main()
你能解释一下为什么会这样吗?
在选择文本之前,我在 Notepad++ 中停顿了很长时间,这表明它陷入了无限循环,而选择所有文本只是它在这样的循环中跳出时的默认行为。
现在,由于这部分 (?:[\w]*\.?)
可以折叠成空,并且可以出现一次或多次,我猜它只是重复匹配任何内容,直到找到匹配 $
的内容。
name ="[\w]+\.((?:[\w$]*\.?)+)" p
似乎工作正常。
更新: 这似乎可以解决您的问题:
name ="\w+\.(?:(\w+\.)*\w+)" p
既然你想知道为什么你的模式不起作用,这里是它的细分:
name =" - capture a literal string: `name ="`
\w+ - ... followed by one or more word characters (A-Za-z0-9_)
\. - ... followed by a literal dot
( - start a capturing group (following matches will be captured as a group)
(?: - start a non-capturing group
\w+ - match one or more word characters (A-Za-z0-9_)
\.? - ... optionally followed by a literal dot
)+ - match as many of these non-capturing groups as possible
) - close the group, nothing is captured as there is no capturing pattern in it
" p - followed by a literal string: `" p`
想像这样的字符串:name ="data.messageHeader.msg_time_tag.$date" pzb
。如果你在上面执行上面的模式,你会很容易地捕获你的 name ="data.
部分,这就是乐趣开始的时候 - 不要介意外部组,问题在于内部组和它后面的 +
限定符 -它将匹配第一个 messageHeader.
,然后它会捕获 msg_time_tag.
等等,直到遇到引号字符...但是,由于 $date
不符合内部模式,它会移动回到 messageHeader.
的上一场比赛(回溯)并再次尝试 - 只是遇到同样的问题,并再次回溯......再次......再次......最终关闭引擎并导致非-可预测的行为。
正则表达式引擎将如何选择处理这个取决于实现 - 最合适的方法是引发 infinite/catastrophic 回溯错误(因为尽管有匹配和模式不提供解决方案),但它可能会因什么都不捕获或捕获所有而失败...
底线是 - 如果您编写正确的正则表达式模式,正则表达式引擎将按预期运行。如果没有 - 一切顺利。
正如 Wiktor 所说,正则表达式将导致灾难性的回溯。具体来说,它是可选的周期,在回溯时,将允许正则表达式尝试搜索字符串的指数排列。以下正则表达式通过强制内部单词后跟句点来防止灾难性回溯。
name ="\w+\.((\w+\.)*\w+)" p