Notepad++中使用否定后顾表达式无法正常工作

22

我有一个源文件,里面有数百个字符串 flecha.jpgflecha1.jpg,但我需要查找任何其他的 .jpg 图像(例如 casa.jpgmoto.jpg 等)

我尝试使用否定的回顾断言来编写正则表达式,像这样:

(?<!flecha|flecha1).jpg

但是它不起作用!Notepad++只是说这是一个无效的正则表达式。

我已经在其他地方尝试了这个正则表达式,这里有一个例子,所以我猜这是NPP处理正则表达式或者lookbehinds/lookaheads语法的问题。

那么我该如何在NPP中实现相同的正则表达式结果呢?

如果有用的话,我正在使用Notepad++版本6.3 Unicode

额外的,如果你愿意,哪种语法可以实现相同的事情并且带有可选的数字后缀(在这种情况下只是'1')?(即使在NPP中它不能工作,只是为了知道)...

我尝试了(?<!flecha[1]?).jpg但它不起作用。它应该和其他的正则表达式一样工作,看这里 (RegExr)

3个回答

19

看起来Notepad++没有实现可变长度的后顾断言(这在某些工具中会发生)。一种解决方法是使用多个固定长度的后顾断言:

(?<!flecha)(?<!flecha1)\.jpg

正如你所看到的,匹配结果是相同的。但这只适用于npp。

请注意,我转义了 . ,因为您正在尝试匹配扩展名,您需要的是字面上的 .。你之前写的是通配符,可以是任何字符。

关于额外的问题,不幸的是,由于我们不能使用可变长度的后顾断言,没有多个后顾断言的情况下不可能有可选的后缀(数字)。


更好的是,您可以使用 [0-9]\d 或类似的表达式,只要每个反向查找的长度保持不变:(?<!flecha)(?<!flecha[1-3])\.jpg - acdcjunior
1
深入挖掘后,我们得到了一个确认:Notepad++使用Boost作为正则表达式实现,而Boost Regex仅支持固定长度的向后查找。 - acdcjunior
太好了!只有一个小疑问关于你的回答;不允许使用变长后顾,这个限制只适用于Npp吗?还是对于Regex和其他工具也适用?也就是说,在其他工具中我可以使用变长后顾吗?或者这是一个RegEx的限制,在其他地方都无法使用? - DiegoDD
再次感谢。我认为所有或至少大多数工具在实现正则表达式时应该有相同的“规则”,但是我发现情况并非如此,它们可能有不同的限制。这很遗憾。应该制定标准以确保正则表达式可以在任何地方工作。感谢您详细的回答/评论! - DiegoDD
2
@acdcjunior,你可能想在你的回答中加入使用Boost的那一部分。 - SQB
显示剩余2条评论

18

解决Notepad++中变长负向回溯断言的问题

以下提供几种策略,以解决在Notepad++(或任何有相同限制的正则表达式引擎)中遇到的这种限制。

问题定义

Notepad++不支持使用变长的负向回溯断言,因此需要一些解决方法。假设我们想避免出现文件名为flecha,并跟随任意数量的数字和任意字符的情况。在这种情况下,利用变长的负向回溯断言的正则表达式看起来像是:(?<!flecha[0-9]*)\.jpg

本示例中不希望匹配的字符串

  • flecha.jpg
  • flecha1.jpg
  • flecha00501275696.jpg
  • aflecha.jpg
  • img_flecha9.jpg
  • abcflecha556677.jpg

解决策略

  1. 插入临时标记

    首先,针对要避免处理的实例,在其上执行查找和替换操作——在本例中,实例为flecha[0-9]*\.jpg。插入特殊标记以形成其他地方不出现的模式。对于此示例,我们将在.jpg之前插入一个额外的.(假设其他位置不存在..jpg)。因此,执行以下操作:

    查找: (flecha[0-9]*)(\.jpg)

    替换为:$1.$2

    现在,您可以使用简单的正则表达式,例如\w+\.jpg(?<!\.)\.jpg来查找文档中的所有其他.jpg文件名,并对它们进行处理。完成后,请执行最终的查找和替换操作,将所有实例的..jpg替换为.jpg,以删除临时标记。
    使用负向先行断言可用于确保不匹配不需要的文件名: (?<!\S)(?!\S*flecha\d*\.jpg)\S+\.jpg 分解:
    - (?<!\S):通过断言匹配不是非空白字符作为前导的内容,确保匹配始于文件名开头而非中间。 - (?!\S*flecha\d*\.jpg):确保匹配的任何内容均不包含要避免的模式。 - \S+\.jpg:这是实际匹配的内容--一串非空白字符后跟.jpg
    如果您知道要避免匹配的模式具有少量可能的长度,则可以使用多个固定长度的负向回顾后发:
    例如,如果我们知道flecha后面只能跟着最多三个数字,则正则表达式可以是: (?<!flecha)(?<!flecha[0-9])(?<!flecha[0-9][0-9])(?<!flecha[0-9][0-9][0-9])\.jpg

你的第三个策略真的救了我的一天。我知道发送感谢不是评论的预期目的,但我仍然想发帖表达感谢。感谢@JoshWithee!对于那些正在处理变量长度的前瞻/后顾,我建议尝试这种不太优雅但有效的方法。 - IggyM
策略一对我很有帮助。谢谢。 - Jonathan Aquino

2

您是否意识到您只匹配(在消耗的意义上)扩展名(.jpg)?我想您希望匹配整个文件名,是吗?使用前瞻更容易实现:

\b(?!flecha1?\b)\w+\.jpg

\b 首先锚定匹配到名称的开头(假设我们正在查看的确实是文件名)。然后 (?!flecha1?\b) 断言该名称不是 flechaflecha1。完成这一步骤后,\w+ 将继续消耗名称。然后 \.jpg 获取扩展名以完成匹配。


1
正如您所注意到的,我只想匹配 .jpg 扩展名。我只想在源文件中查找任何其他图像,而不需要知道它们的文件名,只需知道它们是否存在即可。但还是谢谢!这个答案肯定会对未来有用 =) - DiegoDD

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接