正则表达式:向后看以避免奇数个连续的反斜杠

Posted

技术标签:

【中文标题】正则表达式:向后看以避免奇数个连续的反斜杠【英文标题】:RegEx: Look-behind to avoid odd number of consecutive backslashes 【发布时间】:2012-03-25 16:36:10 【问题描述】:

我有用户输入,其中方括号内允许使用一些标签。我已经编写了正则表达式模式来查找和验证括号内的内容。

在用户输入字段中,左括号([)可以用反斜杠转义,反斜杠也可以用另一个反斜杠(\)转义。我需要后视子模式以避免在打开括号之前出现奇数个连续反斜杠。

目前我必须处理这样的事情:

(?<!\\)(?:\\\\)*\[(?<inside brackets>.*?)]

它工作正常,但问题是这段代码仍然匹配括号前可能的连续反斜杠对(即使它们是隐藏的)并且向后看只是检查是否有另一个单个反斜杠附加到对(或直接打开-括号)。如果可能的话,我需要在后视组中避免它们。

示例:

my [test] string is ok
my \[test] string is wrong
my \\[test] string is ok
my \\\[test] string is wrong
my \\\\[test] string is ok
my \\\\\[test] string is wrong
...
etc

我使用 php PCRE

【问题讨论】:

奇数个数是否有限制? 1、3、5和7是否足以避免?我想你会放过 2,4,6,8 吗? @tchrist 不幸的是,它几乎是无限的。我在我的数据库中找到了一些带有 40 多个连续斜杠的示例。有些人正在使用它们来制作 ASCII '绘图',然后使用标签为某些元素着色或制作超链接。 【参考方案1】:

上次我检查时,PHP 不支持可变长度的lookbehinds。这就是为什么你不能使用简单的解决方案(?&lt;![^\\](?:\\\\)*\\)

最简单的解决方法是简单地匹配整个内容,而不仅仅是括号部分:

(?<!\\)((?:\\\\)*)\[(?<inside_brackets>.*?)]

不同之处在于,现在,如果您在 preg_replace 中使用该正则表达式,您必须记住在替换字符串前加上 $1 前缀,以恢复那里的反斜杠。

【讨论】:

+1 我在手册中发现后视子模式存在一些限制,所以我猜你对可变长度是正确的。匹配整个字符串并拉出括号内的内容不是问题。我现在正在这样做。一些 REGEX 风格允许在后面查看全模式,例如 .NET,但我想知道在 PCRE 中是否可能。顺便说一句,我在 preg_match_all() 中使用了该模式。不过,感谢您的回答。 不,在 PCRE 中是不可能的;整个字符串匹配的东西只是一种解决方法。它提供了相同的功能,但代价是必须自己重新添加这些字符,并从可能的匹配中排除额外匹配的区域。这在这里不是问题,因为有问题的字符串部分只能包含反斜杠,所以那里不能有括号匹配。 @Wh1T3h4Ck5:您接受的正则表达式 (?&lt;![^\\])&lt;etc...&gt; 不正确。它对 negated 字符类(包含反斜杠)进行 negative 后向查找,从而使其成为反斜杠的 positive 后向查找。您需要改用(?&lt;!\\)!我冒昧地编辑了这个答案。 @TimPietzcker - 是的,我之前看到过,但我接受了这个答案,因为我在 PCRE 中的问题没有解决方案,这个答案的开头句子解释了原因。 @Tim,(?&lt;![^\\]) 不等于 (?&lt;=\\)。如果有匹配项,前者将在字符串的开头匹配,而后者需要至少存在一个中间字符(即反斜杠)。是的,我知道您实际上使用的是(?&lt;!\\) 而不是(?&lt;=\\)(正确的是,恕我直言),但我不能让这句话不受质疑。 ;)【参考方案2】:

你可以在没有任何后视的情况下做到这一点((\\\\|[^\\]) 替换除了一个反斜杠之外什么都吃):

^(\\\\|[^\\])*\[(?<brackets>.*?)\] 

【讨论】:

我需要反斜杠作为后视组的一部分。我已经有很多没有后视的解决方案,其中有一个可以完美地发布在上面的问题中。我不需要替代方法如何以另一种方式完成相同的工作。 Etienne Perot 在他的回答中说我正在寻找的东西对于 PCRE 是不可能的,所以我有解决方案相信他错了(我非常怀疑)或者使用 .NET 重写整个项目,因为到目前为止 .NET 只使用 REGEX 风格支持全模式后视。 顺便说一句,您的示例有两个巨大的错误... 1. 锚 ^ 仅在字符串的开头搜索,2. group (\\\\|[^\]) 至少需要一个左括号之前的字符,如果文档以标签开头,则该字符不起作用。 @Wh1T3h4Ck5:将 + 更改为 * 星号,它也适用于字符串的开头。很明显。 @Wh1T3h4Ck5:上面发布的答案确实有追溯,你认为这是什么:(? 是的,伙计,这是我接受这个答案的原因之一。顺便说一句,该答案的模式与我最初在问题中发布的模式完全相同。看看这个例子"This [is] my [test][string]",告诉我你的模式是否匹配所有标签——isthisstring?另外,我的问题是“如果可能,我需要在后视组中避免所有(反斜杠)”,而您的回答却没有做到这一点。根据最初的问题,我希望得到类似“是的,这可能是采用后视模式”或“不,这是不可能的”这样的答案。就这么简单。

以上是关于正则表达式:向后看以避免奇数个连续的反斜杠的主要内容,如果未能解决你的问题,请参考以下文章

贪婪的正则表达式向后看[重复]

积极的向后看没有按预期工作

java 和 JS(javaScript)中的反斜杠正则转义

Python基础要点:字符串和正则表达式中的反斜杠(‘‘)问题详解

正则表达式语法

Java 正则表达式 - 不能以斜杠或空格开始或结束,并且没有连续的斜杠