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_LETTER
、LOWERCASE_LETTER
、TITLECASE_LETTER
、MODIFIER_LETTER
、OTHER_LETTER
、LETTER_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 获取非英文字符的主要内容,如果未能解决你的问题,请参考以下文章