2017-06-05 22 views
1

我不明白为什么下面的正则表达式和文本产生他们的结果。我使用notepad ++中的正则表达式查找功能,没有Wrap_around,也没有匹配的换行符。正则表达式:正则表达式与嵌套组和点导致古怪匹配

name ="[\w]+\.((?:[\w]*\.?)+)" p 

当应用于文本:

名= “data.messageHeader.msg_time_tag $日期” PZB

这是2号线

的整个文本最后突出显示,这应该是不可能的,因为正则表达式不应该匹配美元符号或换行符/回车符。

我也尝试应用正则表达式与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() 

你能解释一下为什么会这样?

+0

你想用这种模式做什么?对于初学者,您试图**捕获**一组多个**非捕获**超前组,在大多数情况下,由于'无限'回溯'会破坏正则表达式引擎(先行组会导致单独的线程在当前位置前面匹配,而当前位置保持在同一位置)。我很坦然地惊讶它甚至没有发生错误。 – zwer

+0

@zwer现在就读起来了......我的目标是捕捉一段由句点分隔的单词。具体来说,我想在第一个单词和第一个句点之后捕获字符串。我需要在我的replace语句中引用该字符串的那部分。 – Derek

+0

@zwer我也应该注意到,当我改变正则表达式来 名= “[\ W] + \((?:[\ W \ $] * \)+?)。” P 它按预期工作,接受美元符号的字符串。 – Derek

回答

0

既然你想知道为什么你的方式不起作用,这里是它的一个细分:

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.并再次尝试 - 只有遇到相同问题,并再次回溯...并再次...并再次......最终关闭引擎并导致不可预测的行为。

正则表达式引擎如何选择处理这取决于实现 - 最正确的方法是提高无限/灾难性的回溯误差(因为搜索头不移动,尽管匹配和模式doesn'牛逼提供的分辨率),但它可能只是通过捕获什么或捕捉一切失败...

的底线是 - 如果你写正确的正则表达式,正则表达式引擎将可预见的行动。如果没有 - 什么都可以。

+0

您所指的前视图不会像您所说的那样移动光标。但是前瞻是由(?= ...或(?<...。)指定的,在我的情况下,我使用(?:...这表示不应该捕获该组,但是这会提前游标。捕获组只是意味着该组不能在反向引用中使用。 – Derek

+0

哎呀,我是不是连看问号后面的符号...我会及时更新。 – zwer

0

在选定文本之前,我在记事本++中长时间停顿,这表明它在无限循环中被捕获,并且选择所有文本只是在打破像这样的循环时的默认行为。

现在,因为此部分(?:[\w]*\.?)可以折叠为无,并且它可以出现一次或多次,我猜它只是重复匹配,直到找到与$匹配的内容为止。

name ="[\w]+\.((?:[\w$]*\.?)+)" p似乎正常工作。

UPDATE: 这似乎是处理你的要求:

name ="\w+\.(?:(\w+\.)*\w+)" p 
+0

您的非转义美元符号代表该行的结尾,对吗?那么这个正则表达式绝对不能匹配任何东西。但更重要的是,我不想匹配任何包含美元符号的字符串。 – Derek

+0

由于括号运算符的性质,不需要转义'[]'中的字符。 –

+0

所以,你会想:'名称= “data.messageHeader.msg_time_tag” pzb'但不是'NAME = “data.messageHeader.msg_time_tag $日期。” pzb'? –

0

正如Wiktor的说,正则表达式会导致灾难性的回溯。具体来说,这是可选的时间段,回溯时,将允许正则表达式尝试搜索字符串的指数排列。以下正则表达式通过强制内部词语后跟句点来防止灾难性回溯。

name ="\w+\.((\w+\.)*\w+)" p