Java - \pL [\x00-\x7F]+ 正则表达式无法使用 String.match 获取非英文字符

Posted

技术标签:

【中文标题】Java - \\pL [\\x00-\\x7F]+ 正则表达式无法使用 String.match 获取非英文字符【英文标题】:Java - \pL [\x00-\x7F]+ regex fails to get non English characters using String.matchJava - \pL [\x00-\x7F]+ 正则表达式无法使用 String.match 获取非英文字符 【发布时间】:2019-06-02 12:21:05 【问题描述】:

我需要验证名称,保存在一个字符串中,它可以是任何语言,使用\pL:

您可以将属于“字母”类别的单个字符与 \pL

匹配

我尝试使用String.matches,但它无法匹配非英文字符,即使是1个字符,例如

String name = "อั";
boolean isMatch = name.matches("[\\pL]+")); // return false

我试过带/不带括号,为多个字母添加+,但总是无法匹配非英文字符

String.matches\pL 一起使用是否有问题?

我使用Pattern 中建议的[\\x00-\\x7F]+ 也失败了

\pASCII All ASCII:[\x00-\x7F]

【问题讨论】:

你的名字只有一个字符? @CarlosHeuberger 不,但即使在一个字符匹配上使用 \pL,它仍然失败 【参考方案1】:

您应该记住,Java 正则表达式将字符串解析为 Unicode 代码单元的集合,而不是代码点。 \pL 匹配来自 BMP 平面的任何 Unicode 字母,它不匹配后面粘有变音符号的字母。

由于您的输入可以包含字母和变音符号,您至少应该在字符类中同时使用 \pL\pM Unicode 属性类:

String regex = "[\\pL\\pM]+";

如果输入字符串可以包含用空格分隔的单词,您可以添加 \s 速记类并匹配任何类型的空格,您可以使用 Pattern.UNICODE_CHARACTER_CLASS 标志编译此正则表达式:

String regex = "(?U)[\\pL\\pM\\s]+";

请注意,此正则表达式允许以任何顺序输入变音符号、字母和空格。如果您需要更精确的正则表达式(例如,只允许在基本字母之后使用变音符号),您可以考虑类似

String regex = "(?U)\\s*(?>\\pL\\pM*+)+(?:\\s+(?>\\pL\\pM*+)+)*\\s*";

这里,(?>\\pL\\pM*+)+ 匹配一个或多个字母,每个字母后跟零个或多个变音符号,\s* 匹配零个或多个空格,\s+ 匹配一个或多个空格。

\pIsAlphabetic[\pL\pM]

如果您检查source code,\pAlphabetic 将检查Character.isAlphabetic(ch) 是否为真。如果 char 属于以下任何类,则为 true:UPPERCASE_LETTERLOWERCASE_LETTERTITLECASE_LETTERMODIFIER_LETTEROTHER_LETTERLETTER_NUMBER 或它具有贡献属性 Other_Alphabetic .它is derived fromLu + Ll + Lt + Lm + Lo + Nl + Other_Alphabetic

虽然所有 L 子类构成了一般 L 类,但请注意 Other_Alphabetic 还包括 Letter number Nl 类,它包含的字符比 \pM 类多,请参阅 this reference(尽管它位于德语,类别和字符名称为英文)。

因此,\pIsAlphabetic[\pL\pM] 更广泛,您应该根据您想要支持的语言做出正确的决定。

【讨论】:

谢谢,为什么比\pIsAlphabetic更好? @user7294900 我添加了更多细节。【参考方案2】:

我找到的唯一解决方案是使用\pIsAlphabetic

\pAlpha 字母字符:\pIsAlphabetic

boolean isMatch = name.matches("[ \\pIsAlphabetic]+")) 

这在https://regex101.com/ in demo 中的站点中不起作用

【讨论】:

【参考方案3】:

那里有两个字符。第一个是字母,第二个是非字母标记。

String name = "\u0e2d";
boolean isMatch = name.matches("[\\pL]+"); // true

有效,但是

String name = "\u0e2d\u0e31";
boolean isMatch = name.matches("[\\pL]+"); // false

不是因为 ั U+E31 是非间距标记 [NSM],而不是字母。

【讨论】:

我会检查它,但它也来自用户输入以及IsAlphabetic 在这种情况下为什么/如何工作? @user7294900。对不起。我的错。我现在看到一个变音符号ัU+E31 合乎逻辑的结论是"[\\pL\\pM]+" 将正确匹配该字符串。【参考方案4】:

用谷歌搜索该字符以找到语言。好像是泰国人。泰语 Unicode 字符范围为:0E00 to 0E7F:

当您使用 unicode 字符时,您可以使用 \u。所以,正则表达式应该是这样的:

[\u0E00-\u0E7F]

REGEX test 中哪个与你的角色相匹配。

如果您想匹配任何语言,请使用:

[\pL]

REGEX test 与您的示例字符匹配。

【讨论】:

我需要英文和非英文字符,不仅是泰文,但感谢泰文参考【参考方案5】:

尝试添加更多类别:

[\pL\pMn\pMc\pNl\pPc\pPd\pPo\pSk]+

请注意,最好不要验证名称。如果他们输入错误但您的系统没有捕捉到它,人们不会真正抱怨。但是,如果有人无法输入他们的名字,那就更成问题了。如果您确实坚持添加验证,使其可覆盖:这应该具有每种方法的优点而没有它们的缺点。

【讨论】:

我必须验证用户输入,你能解释一下类别吗?可以加参考链接/demo吗? @user7294900 我使用en.wikipedia.org/wiki/Unicode_character_property 和compart.com/en/unicode/category 来查找类别。 感谢您的回复,它有效,但它增加了很多问题,例如为什么添加 \pPd 匹配任何类型的连字符或破折号 \pPo 匹配任何类型不是破折号、括号、引号或连接符的标点符号? @user7294900 如果你问为什么 Unicode 标准是这样设计的,我没有任何答案。我也觉得是乱码。如果您要问什么,能否澄清一下您的问题?

以上是关于Java - \pL [\x00-\x7F]+ 正则表达式无法使用 String.match 获取非英文字符的主要内容,如果未能解决你的问题,请参考以下文章

PHP 正则 空字符 / NUL字符

Regex:过滤特殊字符(如日语),但保留表情符号

正则表达式 去除所有非ASCII字符

用java编写程序计算x的n次幂

解析数学函数 PL/SQL

PL/SQL 过程 X 引用视图 Y [关闭]