用于验证本地化字符串中的字母和数字的正则表达式
Posted
技术标签:
【中文标题】用于验证本地化字符串中的字母和数字的正则表达式【英文标题】:Regex for validating alphabetics and numbers in the localized string 【发布时间】:2012-03-18 23:34:08 【问题描述】:我有一个本地化的输入字段。我需要使用正则表达式添加验证,它必须只接受字母和数字。如果我只使用英语,我可以使用[a-z0-9]
。
到目前为止,我正在使用方法Character.isLetterOrDigit(name.charAt(i))
(是的,我正在遍历每个字符)来过滤掉各种语言中存在的字母。
有没有更好的方法?有任何可用的正则表达式或其他库吗?
【问题讨论】:
所以你也想处理英语以外的语言,对吧? 根据this 的帖子,\w
也适用于 perl 的 unicode 字符正则表达式,我不知道在 java 正则表达式中是否如此。
@beerbajay 这不再完全正确,它仍然是标准,但Pattern.UNICODE_CHARACTER_CLASS
启用了预定义字符类和 POSIX 字符类的 Unicode 版本。
@ManuPK 请注意,在 Java 中使用 charAt
总是错误的。你应该打电话给codePointAt
,并相应地调整你的i
。
我必须指出您使用了“字母”一词。我相信,你真正的意思是脚本。顺便提一句。请注意,答案中提到的正则表达式会捕获所有数字,包括Roman Numerals。您可能还想了解Unicode Regular Expressions。
【参考方案1】:
从 Java 7 开始,您可以使用 Pattern.UNICODE_CHARACTER_CLASS
String s = "Müller";
Pattern p = Pattern.compile("^\\w+$", Pattern.UNICODE_CHARACTER_CLASS);
Matcher m = p.matcher(s);
if (m.find())
System.out.println(m.group());
else
System.out.println("not found");
如果没有该选项,它将无法识别“Müller”这个词,而是使用Pattern.UNICODE_CHARACTER_CLASS
启用预定义字符类和 POSIX 字符类的 Unicode 版本。
见here for more details
您还可以查看 Java 7 中的 here for more Unicode information。
这里是regular-expression.info Unicode 脚本、属性和块的概述。
See here a famous answer from tchrist 关于 Java 中正则表达式的警告,包括 Java 7 更改的更新内容(将在 Java 8 中)
【讨论】:
当然这也会匹配下划线和其他连接标点符号。 @TimPietzcker 没错,如果这很重要,那么您的答案将是 OP 的更好选择(为您 +1) @TimPietzcker 在UNICODE_CHARACTER_CLASS
下,所谓的POSIX 类也与UTS#18 Annex C 匹配;也就是说,\palpha
变为 - 当且仅当在 Pattern
编译标志下编译时 - 完全等于 Unicode Alphabetic=True
属性,这本身有点复杂但非常有用,并且不包括连接符标点符号。对不起,连续的句子。 :)
只是添加到这个答案中,Unicode 字符类可以通过嵌入表达式 ?U 启用,如 Pattern class documentation 中所述。【参考方案2】:
boolean foundMatch = name.matches("[\\pL\\pNd]*");
应该可以。
[\pL\pNd]
匹配 Unicode 字母或数字字符。正则表达式.matches()
方法确保整个字符串与模式匹配。
【讨论】:
可以在here找到其他可能的unicode类别(例如L
或N
)。
7大类不需要大括号。你可能还喜欢\pM
,所以[\pL\pM\pN]
。请注意,这已经是比\pAlphabetic
更广泛的定义,因为它包括所有标记,而不仅仅是其中的一部分。这使它更接近用于程序标识符的\pword
属性,每个UTS#18 Annec C 是[\palpha\pgc=Mark\pgc=Digit\pgc=Pc]
,其中\palpha
很复杂,但基本上只选择了几个标记。
@TimPietzcker 等一下:你的布尔测试是错误的。所有可能的字符串都匹配任何内容的零次或多次重复。我不认为你想要那颗星。此外,正如其他地方所评论的那样,虽然它可能是你想要的,\pN
不仅仅是数字; \pNd
只是十进制数字,没有罗马数字、粗俗分数、下标和上标等。只需调用 \pN
任何数字,而不是任何数字,你会是对的。
@tchrist:matches()
方法要求正则表达式匹配整个输入字符串,而不仅仅是一个子字符串。因此,它仅在整个字符串由字母/数字组成(或者为空,这也可以满足该定义)时才匹配。关于\pNd]
的好点。【参考方案3】:
有些人在遇到问题时会想“我知道,我会用 正则表达式。”现在他们有两个问题。
-- Jamie Zawinksi
我开玩笑地说,但是像你正在做的那样迭代字符串将具有运行时性能至少与任何正则表达式一样好 - 正则表达式无法更快地完成你想要的;而且您一开始就没有编译模式的开销。
只要:
验证不需要做任何其他类似正则表达式的事情(问题中没有提到) 通过字符串循环的代码的意图很明确(如果没有,请重构直到它是)那为什么仅仅因为可以用正则表达式替换它呢?
【讨论】:
通过测量来支持这一说法会很有趣。 +1 你可以同意或不同意,这真是一个有趣的链接! @Tim:你甚至不需要测量。除非您使用量子计算,否则您无法在不访问每个字符的情况下验证字符列表(也称为字符串)中的所有字符是否都是字母或数字,并且一旦发现不是字符就停止。由于这是自定义代码所做的,因此它是尽可能少的工作量。正则表达式并不神奇。 正则表达式比手工编码更容易做对。例如,您是否记得使用codePointAt
而不是 OP 使用的错误 charAt
?正则表达式已经为您处理好了。 Handrolled 代码可以像正则表达式一样紧凑,但通常不是。这取决于你想投入多少时间来制作它,以及制作正则表达式库的人投入多少时间。正则表达式可以替换复杂的、容易出错的代码页面。始终首先使用正则表达式,然后仅在分析证明需要时才进行优化。程序员时间赢了。
@tchrist: Always use the regex first, then optimize later only if profiling proves this is needed
。 Programmer time wins
。这两个陈述经常相互矛盾——当他们这样做时,经常会出现一个过于复杂的正则表达式。我完全同意第二个说法,但不一定是第一个。如果我们将“正则表达式”这个词改为“简单的解决方案”(正则表达式通常是,但并不总是直接的解决方案,尤其是在 Java 中),那么我在很大程度上同意你的看法。以上是关于用于验证本地化字符串中的字母和数字的正则表达式的主要内容,如果未能解决你的问题,请参考以下文章