从字符类中排除字符

30

是否有一种简单的方式可以匹配一个字符类中除了特定一组字符以外的所有字符?例如,如果在一种语言中我可以使用\w来匹配所有Unicode单词字符的集合,那么有没有一种方法可以从该匹配中排除下划线“_”这个字符?

我能想到的唯一主意是在每个字符周围使用负向前/后查看,但当我实际上只想将一个字符与正匹配和负匹配相匹配时,这似乎比必要更复杂。例如,如果&是AND运算符,我可以这样做......

^(\w&[^_])+$

4
你使用的正则表达式是哪种语言的?(例如 Perl、Java 等) - Thomas Langston
正则表达式的语言/风格是什么?https://dev59.com/qHA75IYBdhLWcg3wm6ax - Matt Ball
1
在.NET中,您可以使用[\w-[_]]来排除下划线。 - HamZa
我最常用的正则表达式引擎是基于Java的,尽管它是一个旧版本的实现(无论CF8在底层使用什么)。然而,我也需要在JavaScript和Python中使用它。 - Dan Roberts
你是指ColdFusion吗?它基于JavaScript,而不是Java。它的 \w 只识别ASCII单词字符([A-Za-z0-9_]),而不是完整的Unicode集。Python内置的 re 也是同样的情况。 - Alan Moore
Perl的解决方案可以在这里找到。 - ikegami
5个回答

30

这实际上取决于您使用的正则表达式工具。

.NET

...仅提供一种简单的字符类集运算:减法操作。这对于您的示例已经足够了,所以您可以简单地使用

[\w-[_]]

如果一个 - 后面跟着一个嵌套的字符集,就会发生减法操作。就是这么简单...

Java

...提供了一组更丰富的字符类集合操作。特别是您可以像 [[abc]&&[cde]] 这样获取两个集合的交集(在这种情况下将给出 c )。交集和取反结合在一起就能实现减法操作:

[\w&&[^_]]

Perl

……作为一项实验性功能(自 Perl 5.18 起可用),支持在扩展字符类上进行集合操作。特别地,您可以直接从任意字符类中减去:

(?[ \w - [_] ])

其它所有口味

...(支持前瞻的)都允许您通过使用负向前瞻来模拟减法:

(?!_)\w

首先检查下一个字符不是 _ ,然后匹配任何一个 \w (由于负向先行断言,它不能是 _ )。

请注意,这些方法都是完全通用的,因为您可以从两个任意复杂的字符类中减去。


14
你可以使用排除 \w 类(--> \W) 的方法:
^([^\W_]+)$

创意十足,但我认为原帖的作者并没有期望这种类型的回答,他想要在一般情况下排除一个字符。不过这个想法很好。 - HamZa
@CasimiretHippolyte 我应该想到这个的。HamZa是对的,我正在寻找一个更一般的情况,但哇... \p...感谢您指出来,因为我从未使用过它。 - Dan Roberts
@CasimiretHippolyte 不是所有情况都适用。这不能用于从范围中排除字符 ;)。 - Martin Ender
@caw:你的例子超出了问题的范围,除了正则表达式支持字符类内操作(交集、减法)的情况外,我怀疑没有神奇的解决方案(不使用手指通过范围构建它)。然而,对于你的特定示例,你可以在unicode模式下使用pcre来实现:[[:alnum:]\pP][\p{Xan}\pP]。换句话说,你必须找到每种情况的最佳解决方案,并使用预定义的类。 - Casimir et Hippolyte
@caw:如果我的回答看起来很粗鲁,我对英语并不是完全流利。欢迎您的评论和批评。感谢您的“完美答案”,其他答案也很有用。 - Casimir et Hippolyte
显示剩余4条评论

11

就我理解你的问题,负向先行断言是正确的方法:

^((?!_)\w)+$

8
这可以在Python中使用正则表达式模块完成。例如:
import regex as re
pattern = re.compile(r'[\W_--[ ]]+')
cleanString = pattern.sub('', rawString)

一般情况下,您可以使用pip安装正则表达式模块:

pip install regex

编辑:

正则表达式模块有两种行为,版本0和版本1。设置子字符串(如上所述)是版本1的行为。 pypi文档声称版本1是默认行为,但您可能会发现情况并非如此。您可以使用以下命令进行检查:

import regex
if regex.DEFAULT_VERSION == regex.VERSION1:
  print("version 1")

将其设置为版本1:
regex.DEFAULT_VERSION = regex.VERSION1

或者在单个表达式中使用第一版本:

pattern = re.compile(r'(?V1)[\W_--[ ]]+')

版本1位上的救星。否则我会疯掉的。 - edA-qa mort-ora-y

6

尝试使用减法:

[\w&&[^_]]+

注意:这将在Java中工作,但可能不适用于其他某些正则表达式引擎。

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