验证本地化字符串中字母和数字的正则表达式

15

我有一个已经进行了本地化的输入框。 我需要使用正则表达式添加验证,以确保它只接受字母和数字。 如果我只使用英语,我可以使用[a-z0-9]

目前,我正在使用Character.isLetterOrDigit(name.charAt(i))方法(是的,我正在迭代每个字符)来过滤出各种语言中存在的字母。

是否有更好的方法? 是否有任何正则表达式或其他库可用于此?


所以你想处理除了英语之外的其他语言,对吗? - Lukasz
1
根据这篇帖子,\w在perl的正则表达式中也适用于Unicode字符,我不知道Java的正则表达式是否也是如此。 - user1227804
4
@beerbajay 这不再完全正确,虽然它仍然是标准,但Pattern.UNICODE_CHARACTER_CLASS启用了预定义字符类和POSIX字符类的Unicode版本。 - stema
1
@ManuPK 请注意,在Java中使用 charAt 总是错误的。你应该调用 codePointAt,并相应地调整你的 i - tchrist
1
我必须指出,你使用了“字母表”这个术语。我相信你真正想表达的是“字符集”。顺便说一句,请注意,答案中提到的正则表达式捕获所有数字,包括罗马数字。你可能还想阅读有关Unicode正则表达式的内容。 - Paweł Dyda
显示剩余3条评论
3个回答

24

自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版本。

在Java 7中此处可以查看更多详细信息

您还可以在Java 7中此处查看更多有关Unicode的信息

在此处查看Unicode脚本、属性和块的概述

在此处查看tchrist所提供的一份著名答案,其中包括Java正则表达式的注意事项及Java 7中已更改的内容(或者将在Java 8中更改)


当然,这也将匹配下划线和其他连接标点符号。 - Tim Pietzcker
@TimPietzcker 没错,如果这很重要的话,那么你的答案对于 OP 来说会是更好的选择(+1 给你)。 - stema
UNICODE_CHARACTER_CLASS下,所谓的POSIX类也会匹配UTS#18 Annex C中的内容;也就是说,如果且仅当在Pattern编译标志下编译时,\p{alpha}将完全等同于Unicode Alphabetic=True属性,该属性本身有些复杂但非常有用,并且不包括连接符标点符号。抱歉句子有点长。 :) - tchrist
1
仅仅是为了补充这个答案,Unicode字符类可以通过嵌入表达式?U启用,正如Pattern类文档中所提到的。 - Paweł Dyda

10
boolean foundMatch = name.matches("[\\p{L}\\p{Nd}]*");

应该可以工作。

[\p{L}\p{Nd}] 匹配一个Unicode字母或数字。正则表达式的 .matches() 方法确保整个字符串与模式匹配。


1
其他可能的Unicode类别(例如“L”或“N”)可以在此处找到:http://www.fileformat.info/info/unicode/category/index.htm。 - beerbajay
对于7个主要类别,您不需要使用大括号。您可能还喜欢\pM,因此使用[\pL\pM\pN]。请注意,这已经是比\p{Alphabetic}更广泛的定义,因为它包括所有标记,而不仅仅是其中一些。这使其更接近用于程序标识符的\p{word}属性,根据UTS#18 Annec C,它是[\p{alpha}\p{gc=Mark}\p{gc=Digit}\p{gc=Pc}],其中\p{alpha}很复杂,但基本上只选择了一些标记。 - tchrist
@TimPietzcker 别急:你的布尔测试是错误的。所有可能的字符串都匹配零个或多个任意字符的重复。我认为你不想要那个星号。此外,正如在其他地方评论的那样,虽然这可能是你想要的,\pN 不仅仅代表数字; \p{Nd} 只是没有罗马数字、分数、上下标等的十进制数字。只需将 \pN 称为任何数值,而不是任何数字,你就会明白了。 - tchrist
@tchrist:matches() 方法要求正则表达式匹配整个输入字符串,而不仅仅是子字符串。因此,它只有在整个字符串由字母/数字组成(或为空,这也可以算作符合该定义)时才匹配。\p{Nd} 的观点很好。 - Tim Pietzcker

1
有些人遇到问题时,会想:“我知道,我用正则表达式。”现在他们有两个问题了。
-- Jamie Zawinksi
我是开玩笑的,但像你现在这样迭代字符串的方式,其运行时性能至少和任何正则表达式一样好。没有任何一种正则表达式可以比你更快地完成你想要的操作;而且你也不需要先编译一个模式,这样就没有了额外的开销。
所以只要:
  • 验证不需要做任何类似于正则表达式的事情(问题中没有提到)
  • 代码循环遍历字符串的意图是清晰的(如果不是,请重构代码直到它变得清晰明了)
那么为什么要因为你会使用正则表达式就用它来替换掉原本的代码呢?

2
通过测量来支持这个说法会很有趣。 - Tim Pietzcker
+1 好的,你可以同意或不同意,这确实是一个有趣的链接! - ManuPK
@Tim:你甚至不需要测量。除非你使用量子计算,否则你无法验证字符列表(也称为字符串)中的所有字符是否为字母或数字,而不访问每个字符,并在找到一个不是字母或数字的字符时停止。由于这就是自定义代码所做的,因此这是最小可能的工作量。正则表达式并不是魔法。 - Sean Reilly
3
正则表达式通常比手动编写代码更准确。例如,你是否会记得使用 codePointAt 而不是 OP 所使用的错误的 charAt?而正则表达式已经替你处理了这个问题。手写代码可能与正则表达式一样紧凑,但通常并不如此。这取决于你愿意花多少时间来精心编写它,以及那个编写正则表达式库的人花了多少时间来制作它。一个正则表达式可以替换掉数页复杂、容易出错的代码。始终先使用正则表达式,然后仅在性能测试证明需要时才进行优化。程序员的时间胜出。 - tchrist
@tchrist: “始终先使用正则表达式,只有在分析证明需要优化时才进行优化”。“程序员的时间胜利”。这两个陈述经常相互矛盾——当出现过于复杂的正则表达式时,它们通常存在。我完全同意第二个陈述,但不一定同意第一个。如果我们将“正则表达式”改为“简单直接的解决方案”(在Java中,正则表达式通常是但并非总是简单明了的解决方案),那么我会大体上同意您的观点。 - Sean Reilly

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