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

17

我有一个正则表达式,想要对其进行否定,例如:

/(.{0,4})

String.matches返回以下结果

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

有没有一种只使用正则表达式来实现上述相反的方法,使得结果为:

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

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

我已经查看了以下内容 如何否定整个正则表达式?使用 (?! pattern),但这对我似乎不起作用。

以下是正则表达式:

(?!/(.{0,4}))

返回以下内容:

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

这不是我想要的。 非常感谢您的帮助。


4
你能否只匹配并否定是否匹配呢?这是任何不需要重写正则表达式的通用解决方案。 - Dave Newton
2
这个匹配编码是现有框架的一部分,如果更改它会破坏其他东西。 - Wayne
3个回答

39

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

/.{0,4}

该正则表达式匹配包含斜杠后跟零到四个字符的字符串。但是,由于您正在使用matches()方法,它会自动锚定,就好像它实际上是:

^/.{0,4}$
为了实现其反向操作,您不能依赖于自动锚定; 您必须在预查中至少明确指定结束锚定。您还必须使用 .* “填充”正则表达式,因为 matches()要求正则表达式消耗整个字符串:
(?!/.{0,4}$).*

但我建议您显式锚定整个正则表达式,像这样:

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

这并不会造成任何伤害,而且可以让你的意图变得非常明确,特别是对于那些从其他语言(如Perl或JavaScript)学习过正则表达式的人。 matches() 方法的自动锚定非常不寻常。


这对于任何正则表达式都有效吗?例如 String negateRegex(String regex) { return "(?!" + regex + "$).*"; } 是否能按预期工作?它能否否定自身?也就是说,negateRegex(negateRegex(regex)) 的功能是否与 regex 相同? - Mark
嗯,我在这里做了一些初步的测试[1],它似乎在我尝试过的所有情况下都能正常工作,包括否定否定。 [1] http://www.regexplanet.com/advanced/java/index.html - Mark
我不相信你可以像操作字符串一样操作正则表达式。你考虑过\Q和\E吗?你考虑过末尾的反斜杠吗? - ntysdd

8

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

虽然Alan Moore的答案几乎是正确的。你需要将整个正则表达式分组,否则你会冒着仅将原始正则表达式的一部分作为定位点的风险。

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

在正则表达式前添加(?!并在后面添加$).*。你最终会得到(?!abc|def$).*

这里锚点仅适用于def,这意味着当它应该匹配时,"abcx"不会匹配。

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

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

根据我的测试,似乎negateRegex(negateRegex(regex))regex的功能是一样的。


0
假设我们的正则表达式是MYREG,用以下方式匹配其它行:
^(?:(?!.*MYREG).*)$

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