如何否定Java中的任何正则表达式

Posted

技术标签:

【中文标题】如何否定Java中的任何正则表达式【英文标题】:how to negate any regular expression in Java 【发布时间】:2012-01-26 11:59:57 【问题描述】:

我有一个想要否定的正则表达式,例如

/(.0,4)

which String.matches 返回以下内容

"/1234" true
"/12" true
"/" true
"" false
"1234" false
"/12345" false

有没有办法对上述内容进行否定(仅使用 regx),结果是:

"/1234" false
"/12" false
"/" false
"" true
"1234" true
"/12345" true

我正在寻找一种通用解决方案,它适用于任何正则表达式,而无需重写整个正则表达式。

我看过以下 How to negate the whole regex? 使用 (?! 模式),但这似乎对我不起作用。

以下正则

(?!/(.0,4))

返回以下内容:

"/1234" false
"/12" false
"/" false
"" true
"1234" false
"/12345" false

这不是我想要的。 任何帮助将不胜感激。

【问题讨论】:

你不能只匹配并否定它是否匹配吗?这是任何不重写正则表达式的正则表达式的通用解决方案。 这个匹配的编码是现有框架的一部分,如果不破坏其他东西就无法更改。 【参考方案1】:

您需要添加锚点。原始正则表达式(减去不需要的括号):

/.0,4

...匹配包含一个斜线后跟零到四个字符的字符串。但是,因为您使用的是 matches() 方法,所以它会自动锚定,就好像它真的是:​​

^/.0,4$

要实现相反的效果,您不能依赖自动锚定;您必须至少在前瞻中明确结束锚点。您还必须使用.*“填充”正则表达式,因为matches() 要求正则表达式消耗整个字符串:

(?!/.0,4$).*

但我建议您明确锚定整个正则表达式,如下所示:

^(?!/.0,4$).*$

它没有害处,它让你的意图非常清楚,尤其是对于那些从 Perl 或 javascript 等其他风格学习正则表达式的人。 matches() 方法的自动锚定非常不寻常。

【讨论】:

那么这适用于任何正则表达式吗?即String negateRegex(String regex) return "(?!" + regex + "$).*"; 会按预期工作吗?这可以否定自己吗?即negateRegex(negateRegex(regex)) 在功能上是否与regex 相同? 嗯,我在这里做了一些初步测试[1],它似乎在我尝试过的所有情况下都有效,包括否定否定。 [1]regexplanet.com/advanced/java/index.html 我不相信你可以像字符串一样操作正则表达式。你考虑 \Q 和 \E 吗?您是否考虑最后的反斜杠?【参考方案2】:

我知道这是一个非常古老的问题,但希望我的回答可以帮助任何将来寻找这个问题的人。

虽然Alan Moore 的回答几乎是正确的。您还需要对整个正则表达式进行分组,否则您可能会仅锚定原始正则表达式的一部分。

例如,如果您想否定以下正则表达式:abc|def(匹配 "abc""def"

附加(?! 和附加$).*。你最终会得到(?!abc|def$).*

这里的anchor只适用于def,意思是"abcx"应该不匹配。

我宁愿在(?!(?:前面加上)$).*

String negateRegex(String regex) 
    return "(?!(?:" + regex + ")$).*";

从我的测试来看,negateRegex(negateRegex(regex)) 在功能上确实与regex 相同。

【讨论】:

以上是关于如何否定Java中的任何正则表达式的主要内容,如果未能解决你的问题,请参考以下文章

正则表达式的否定

否定正则表达式中的特定字符

带有`\R`的Java-8 正则表达式否定回溯

java中的正则表达式

用于查找 HTML 标签及其内容的正则表达式的否定 - java

正则表达式背后的 pl/sql 否定查看