Regex 记事本中的Bug++;/正则表达式中的BOOST还是bug?

Regex 记事本中的Bug++;/正则表达式中的BOOST还是bug?,regex,notepad++,Regex,Notepad++,我有一个结构如下的文件: Line foo Änderbar: PM baz Line Line foo Änderbar: OM baz Line Line foo Änderbar: ++ baz Line Line foo Änderbar: -- baz Line 因此,该文件由新行分隔的“块”组成(我已将该文件转换为Unix行结尾)。每个块可以有任意数量的行。块的每一行至少包含一个非换行字符,并由换行字符完成。分隔块的行正好由一个换行符组成 在每个块中,只有一行采用以下格式:

我有一个结构如下的文件:

Line
foo Änderbar: PM baz
Line

Line
foo Änderbar: OM baz
Line

Line
foo Änderbar: ++ baz
Line

Line
foo Änderbar: -- baz
Line
因此,该文件由新行分隔的“块”组成(我已将该文件转换为Unix行结尾)。每个块可以有任意数量的行。块的每一行至少包含一个非换行字符,并由换行字符完成。分隔块的行正好由一个换行符组成

在每个块中,只有一行采用以下格式:

  • 至少一个非换行字符,后跟
  • 文本字符串
    “Änderbar:”
    ,后跟
  • 正好是一个文本字符串
    '+'
    '-'
    'OM'
    'PM'
    ,后跟
  • 至少一个非换行字符,后跟
  • 以换行符结尾的行
在同一块中,此专用线上方和下方始终至少有一条非空行

我需要一种有效的方法来查找(并因此选择)所有块,其中
下一条:
后面的文字是
--
(查找/选择一个又一个块,再次点击
查找下一个
,即不同时选择所有这些块)

通常,我用记事本++解决这些问题很有趣。然而,在这种情况下,随着年龄的增长,我似乎变得越来越愚蠢,或者在Notepad++的正则表达式处理引擎中有一个bug

Notepad++使用BOOST(并通过BOOST支持PCRE表达式)。因为这是广泛使用的,我认为这个问题很重要,在这里发布它,只是为了真正的促进是错误行为的原因。

说到这里:我将该文件加载到Notepad++,启动搜索和替换对话框,勾选
。匹配换行符
,勾选
正则表达式
,并在
查找内容:
文本框中输入以下正则表达式:

\n([^\n]+\n)+[^\n]+(Änderbar\:\ --[^\n]+\n)([^\n]+\n)+
我非常惊讶,这使得记事本++的行为异常:当光标被放置在紧靠
工具栏--
的块前面的空行中时,点击
Find Next
按预期找到/选择了该块。但是当光标位于另一个位置时,点击
Find Next
Notepad++Find/选择文件的其余部分,即光标位置下方的所有块

然后,我测试了它是否会发现块在
下栏:
之后有
++
,也就是说,我将regex改为

\n([^\n]+\n)+[^\n]+(Änderbar\:\ \+\+[^\n]+\n)([^\n]+\n)+
猜猜看:这在每种情况下都能可靠地工作。最后两种情况也是如此:

\n([^\n]+\n)+[^\n]+(Änderbar\:\ PM[^\n]+\n)([^\n]+\n)+
\n([^\n]+\n)+[^\n]+(Änderbar\:\ OM[^\n]+\n)([^\n]+\n)+
因此,记事本++/PCRE似乎在某些情况下对
-
的正确解释有问题,或者我的正则表达式中有一个微妙的错误,只有在搜索
-
(而不是
++
OM
PM
)时才会触发

请注意,我已经尝试在空格字符前面去掉
\
(这实际上只会使情况变得更糟,但我只是以防万一),并且我还尝试使用
\-\-
而不是
-
(尽管后者应该可以)。这并没有以任何方式改变(错误)行为

那么这里的问题是什么?我的正则表达式中是否有bug,或者记事本++中是否有bug

更新

我已经剥离了有问题的实际文件,并将其上载到。要重现此问题,请执行以下操作:

  • 从上面的链接下载文件并将其保存在硬盘上的某个位置(不要将文本直接复制到记事本++)

  • 将文件加载到记事本++。光标现在位于最上面一行,未选择任何内容

  • 这很重要:单击编辑->下线转换->Unix(LF)

  • 确认光标仍在最顶行(为空)且未选择任何内容

  • 打开“查找”对话框,选择设置并输入如上所述的搜索字符串

  • 单击“查找下一步”

  • 请注意,现在已找到/选择完整文本

  • 保持Find窗口打开,删除文件的第三行(它读作“Funktionspaket(e):ML”)。不要只是清空那一行,而是真正地删除它,这样在前一行和后一行之间就没有空行了

  • 同样,将光标放在最上面的一行(仍然为空),并确保未选择任何内容

  • 单击“查找下一步”

  • 请注意,正则表达式现在可以按预期工作


显然,有人想愚弄我,对吧?

这不是一个bug。您只是忘记了一件非常重要的事情—对于Windows行结尾,您的行在
\n
之前有一个
\r
,因此正则表达式的
\n([^\n]+\n)+
部分也会匹配您的空行,这就是为什么单击“查找下一步”会匹配光标位置而不是块开头的所有内容


转到编辑>下线转换>Unix(LF),您将看到它现在可以工作了。如果您想支持Windows和Unix行结束符,您必须将每个
[^\n]
更改为
[^\r\n]
,将每个
\n
更改为
\r?\n

我认为关键是:您需要以
^
开始正则表达式(行的开头)

您的原始正则表达式变成:

^\n([^\n]+\n)+[^\n]+(Änderbar\:\ --[^\n]+\n)([^\n]+\n)+
但您可以通过以下方式简化:

^\R(?:.+\R)+.+Änderbar: --.+\R(?:.+(?:\R|\z))+
注意:勾选
。匹配换行符
其中:

  • \R
    匹配任何类型的换行符,无需更改下线
  • \z
    匹配文件的结尾,如果不使用它,如果没有换行符,则无法匹配文件的最后一行
  • (?:…)
    是一个非捕获g