正则表达式非运算符

279
正则表达式中是否有非运算符?
例如在以下字符串中:"(2001) (asdf) (dasd1123_asd 21.01.2011 zqge)(dzqge) name (20019)" 我想要删除所有的\([0-9a-zA-z _\.\-:]*\),但不包括年份的情况:(2001)
因此正则表达式应该返回:(2001) name
注意:像\((?![\d]){4}[0-9a-zA-z _\.\-:]*\)这样的表达式不能满足我的需求((20019)也匹配了...)。

1
有一个类似上面的字符串,我想用正则表达式处理它,希望得到的结果是:(2001) name - Sonnenhut
4个回答

425

不完全正确,虽然通常可以在其中一种形式上使用某些变通方法。

  • [^abc],逐个字符表示不是 abc
  • 或负向先行断言:a(?!b),表示 a 不跟随 b
  • 或负向后行断言:(?<!a)b,表示 b 不在 a 之前

1
是的,我认为负向后顾是(?<!a)b -- 参考:http://www.regular-expressions.info/lookaround.html - jankins
32
[^abc] 应该表示不是 a 或者 b 或者 c,而不是 "不是字符串 abc". - VimNing
谢谢。%[^sdf]%(?!(s|d|f)) 等同于“包含 %”,但不包括“%s”、“%d”或“%f”。 - CoolMind
2
负向预查和负向回顾也允许轻松否定多个字母,例如 you(?!tube)(?<!docker)hub - Jonas Eicher
a(?!b)(a后面不跟着b)非常出色。最佳答案。 - Avatar

197

不,没有直接的非运算符。至少不是你希望的那种方式。

然而,你可以使用零宽度负向先行断言:

\((?!2001)[0-9a-zA-z _\.\-:]*\)

(?!...)的意思是“只有在该文本后面(因此:前瞻)的文本(因此:否定)匹配时才进行匹配。但它实际上并不会消耗它匹配的字符(因此:零宽度)。

实际上,有2个轴和4种lookarounds的组合:

  • 向后查找/向前查找:指定是否考虑点之前之后的字符
  • 正向/负向:指定字符必须匹配还是不能匹配。

1
谢谢你!“?!”也是我建议的,但是无论如何,如果我使用\((?![\d]{4})[0-9a-zA-z _\.\-:]+\),它仍然包含(20019) - Sonnenhut
在您的问题编辑中,您将{4}放在了前瞻之外,在这个评论中,您将其放在了前瞻之内:您尝试了哪一个?另外:如果您想匹配(20019),那么您必须在前瞻内添加\)\((?![\d]{4}\))[0-9a-zA-z _\.\-:]+\) - Joachim Sauer
使用上述的正则表达式在您的注释中,它可以正常工作。但是我不明白那个...我不明白为什么要转义以下部分\((?![\d]{4} -->\)<--)[0-9a-zA-z _\.\-:]+\)。然后这里有一个未关闭的括号,是吗? - Sonnenhut
1
我转义闭合的括号 ),因为我想匹配字面上的字符 )(就像在你的正则表达式开头和结尾所做的一样!)。然后,在匹配成功后,我使用未转义的 ) 结束前瞻。 - Joachim Sauer
明白了。那些字符让我有点困惑。谢谢。 - Sonnenhut
显示剩余2条评论

1

这里有一个替代方案:

(\(\d{4}\))((?:\s*\([0-9a-zA-z _\.\-:]*\))*)([^()]*)(( ?\([0-9a-zA-z _\.\-:]*\))*)

使用这种结构,将重复模式嵌入到单个组中,其中内部组不是捕获组:((:?pattern)*),可以控制感兴趣的组号。

然后,您可以使用以下内容获取所需内容:\1\3


1
你可以捕获(2001)部分,并将其余部分替换为空。
public static string extractYearString(string input) {
    return input.replaceAll(".*\(([0-9]{4})\).*", "$1");
}

var subject = "(2001) (asdf) (dasd1123_asd 21.01.2011 zqge)(dzqge) name (20019)";
var result = extractYearString(subject);
System.out.println(result); // <-- "2001"

.*\(([0-9]{4})\).* 的意思是

  • .* 匹配任何字符
  • \( 匹配一个 ( 字符
  • ( 开始捕获
  • [0-9]{4} 匹配四个数字
  • ) 结束捕获
  • \) 匹配一个 ) 字符
  • .* 匹配任何字符 (剩余字符串)

使用全局正则表达式标志 .replace(),因为很多浏览器和 Node 不支持 .replaceAll() - Lorik
6
@lorikku java != javascript 的意思是“Java 不等于 JavaScript”。 - zyexal
@zyexal 哦,糟糕!我没意识到它是Java哈哈,我的错! - Lorik

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