正则表达式:如何在不使用下划线的情况下表示\w

51

有没有一种简洁的表达方式:

\w but without _

也就是说,“所有包含在\w中的字符,除了下划线”

我提出这个问题是因为我正在寻找表达域名验证最简洁的方式。域名可能包括小写和大写字母、数字、句点和破折号,但没有下划线。\w包括以上所有内容,还有一个下划线。那么,有没有办法通过正则表达式语法从\w中“去除”下划线?

编辑:我所问的是PHP中使用的正则表达式。

提前感谢!


6
取决于正则表达式的类型。你正在使用哪种语言?最简单的方法是只使用[A-Za-z0-9]\w通常不包括连字符或句号。 - Felix Kling
1
根据不同的编程语言,\w 可能支持 Unicode 字符。除非你完全确定 \w 代表什么,最好使用字符类 [] 并列出所有常规字符。 - nhahtdh
8个回答

63

以下是 Perl 中的字符类:

[^\W_]

\W[^\w]相同。


1
@protist:原子是错误的。\w将匹配_,而|是交替并且像OR一样起作用,而不是AND。 - nhahtdh
抱歉,我之前应该提到了。我正在使用PHP。在PHP中可以吗? - Dimitri Vorontzov
所以,我理解得对吗,[^\W_]和[A-Za-z0-9.-]是一样的? - Dimitri Vorontzov
1
我不确定.-是否包含在内,因为什么被认为是“单词”字符在不同的语言环境下略有不同。一些来源说\w等同于[A-Za-z0-9_](但一定要指出这并不总是正确的)。[^\W_]\w但没有_,尽管如此。 - protist
2
换句话说,可以这样表达:(not (not word) or underscore),其中word是[a-zA-Z0-9_] - Adithya
显示剩余3条评论

18
你可以使用负向先行断言: (?!_)\w。然而,我认为写[a-zA-Z0-9.-]更易读。

1
那应该是(?!_)\w,对吧? - Zero Piraeus
回顾匹配比普通匹配慢。不过在这里可能无关紧要。 - nhahtdh
非常感谢,@Bergi - 我有一个问题:写[a-zA-z0-9.-] - 转义句点和破折号是正确的吗?或者在这种情况下转义它们是错误/不必要的?(我对正则表达式很陌生,这可能是个愚蠢的问题...) - Dimitri Vorontzov
1
只有在字符类中具有特殊含义的字符(]\^-)需要转义,而在不引起歧义的情况下则不需要。 - Bergi
非常感谢您,@Bergi!因此,在查看我的问题的所有答案时,这些解决方案都可以工作:(?!)\w --- [^\W] --- 或 [A-Za-z0-9.-] --- 我是对的吗? - Dimitri Vorontzov
1
@Dimitri:是的,根据你所使用的正则表达式语法,\w 表示 [a-zA-Z0-9.-_] - Bergi

5

为了保险起见,通常我们会使用字符类:

[a-zA-Z0-9.-]

上述的“片段”正则表达式匹配英文字母、数字、点号.和破折号-。即使是基本的正则表达式支持,它也应该可以工作。

较短的表达式可能更好,但前提是你确切知道它代表什么。

我不知道您使用的语言是什么。在许多引擎中,\w等同于[a-zA-Z0-9_](一些要求“ASCII模式”)。然而,一些引擎对正则表达式具有Unicode支持,并且可以扩展\w以匹配Unicode字符。


10
这将排除所有Unicode字符,例如“äö”等。 - MrD
1
@MrD:是的,最好的方法根本不使用正则表达式来进行域验证。 - nhahtdh

3

9
当你有非英文字母时,这会带来问题。 - Zoltán Tamási
@ZoltánTamási 域名,非英文字母? - Kent
3
@Kent - ICANN批准非拉丁字符域名 - Joseph Silber
哦,抱歉我错过了那个。不过据我所知,现在(至少在匈牙利)可以获得带有重音的域名。 - Zoltán Tamási

2
一些正则表达式引擎支持负向回顾后发现语法,您可以使用它:
\w(?<!_)

2
负向先行断言比负向后行断言得到更广泛的支持。 - Joseph Silber
1
@JosephSilber 确实。从概念上讲,如果可以使用负回顾后发,我觉得“给我一个单词字符...但不包括下划线”比“下一个字符不应该是下划线...否则,给我一个单词字符”更容易理解。 - Zero Piraeus

1
对于任何想要匹配 [^a-zA-Z0-9]+ 的人来说,可以简写为 [\W^_]+(在Python中)。
然而,使用 \W 可能会导致微小的性能下降,因为首先匹配的是 [^a-zA-Z0-9_],然后再取消匹配 _
def camelCaseNotation(value):
    """Select all symbolic character plus the next alphabetical character. Remove symbols and uppercases the alphabetic character."""
    return re.sub(r"[\W^_]+([\w]{0,1})", lambda m: m.group(1).upper(), value)

0
你可以写出类似这样的代码:
\([^\w]|_)\u

如果您使用 preg_filter 函数并传入此字符串,那么 \w 中的任何字符(下划线 _ 除外)都将被过滤。

0

我会从 [^_] 开始,然后考虑需要拒绝哪些其他字符。如果你需要过滤键盘输入,枚举所有不想要的字符就很简单了。


2
这是一种非常糟糕的方法。域名有一组定义好的允许字符,因此可以进行白名单处理。当你使用黑名单时,你需要关注你需要拒绝哪些Unicode字符。 - nhahtdh
@nhahtdh,我已经考虑到域名可以包含Unicode字符(例如带重音的元音字母)。因此,我认为很难精确地形成一个最终正确的白名单解决方案。 - Zoltán Tamási
有规格说明书 - 这很麻烦,但是已经定义好了。当黑名单时,人们往往会忘记或忽视一些事情。 - nhahtdh
我同意,这就是为什么我提到如果情况是键盘输入的话,因为在我看来那可以简化事情。 - Zoltán Tamási

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