【问题标题】:Detect non Latin characters with regex Pattern in Java在 Java 中使用正则表达式模式检测非拉丁字符
【发布时间】:2021-04-13 16:04:00
【问题描述】:

我认为拉丁字符是我的问题的意思,但我不完全确定正确的分类是什么。我正在尝试使用正则表达式模式来测试字符串是否包含非拉丁字符。我期待以下结果

"abcDE 123";  // Yes, this should match
"!@#$%^&*";   // Yes, this should match
"aaàààäää";   // Yes, this should match
"ベビードラ";   // No, this shouldn't match
"????????????????";  // No, this shouldn't match

我的理解是,内置的{IsLatin} 预设只是检测是否有任何字符是拉丁语。我想检测是否有任何字符不是拉丁语。

Pattern LatinPattern = Pattern.compile("\\p{IsLatin}");
Matcher matcher = LatinPattern.matcher(str);
if (!matcher.find()) {
    System.out.println("is NON latin");
    return;
}
System.out.println("is latin");

【问题讨论】:

  • 我认为您实际上想检查字符串是否为 ASCII,Pattern LatinPattern = Pattern.compile("\\p{ASCII}");。见ideone.com/FeTIiT
  • 是的,也许 ASCII 就是我的意思。您发布的模式测试是否有任何字符是 ASCII。我有兴趣检测是否有任何字符不是 ASCII。
  • 这个问题自相矛盾。它说"abcDE 123" 应该匹配,但随后抱怨\p{IsLatin} 匹配并说您“想要检测是否有任何字符不是拉丁语”。那么它是哪一个?当字符串包含非拉丁字符时,您希望正则表达式匹配还是不匹配?请编辑问题并阐明您期望从正则表达式中得到什么结果。
  • 仅供参考: \p{IsLatin} 匹配拉丁字符。反向测试\P{IsLatin},使用大写的P,匹配\p{IsLatin} 不匹配的任何内容,即所有非拉丁字符。 \P{IsLatin}[^\p{IsLatin}] 相同。
  • 如果所有字符都是拉丁字符,我希望正则表达式匹配,如果任何字符都是非拉丁字符,则不匹配。这可能吗?

标签: java regex latin


【解决方案1】:

TL;DR: 使用正则表达式^[\p{Print}\p{IsLatin}]*$


如果字符串包含以下内容,您需要一个匹配的正则表达式:

  • 空间
  • 数字
  • 标点符号
  • 拉丁字符(Unicode 脚本“拉丁”)

最简单的方法是将\p{IsLatin}\p{Print} 组合在一起,其中Pattern\p{Print} 定义为:

  • \p{Print} - 可打印字符:[\p{Graph}\x20]
    • \p{Graph} - 可见字符:[\p{Alnum}\p{Punct}]
      • \p{Alnum} - 字母数字字符:[\p{Alpha}\p{Digit}]
        • \p{Alpha} - 字母字符:[\p{Lower}\p{Upper}]
          • \p{Lower} - 小写字母字符:[a-z]
          • \p{Upper} - 大写字母字符:[A-Z]
        • \p{Digit} - 十进制数字:[0-9]
      • \p{Punct} - 标点符号:!"#$%&'()*+,-./:;<=>?@[\]^_`{|}~之一
    • \x20 - 空格:

这使得 \p{Print}[\p{ASCII}&&\P{Cntrl}] 相同,即不是控制字符的 ASCII 字符。

\p{Alpha} 部分与\p{IsLatin} 重叠,但这很好,因为字符类消除了重复。

所以,正则表达式是:^[\p{Print}\p{IsLatin}]*$

测试

Pattern latinPattern = Pattern.compile("^[\\p{Print}\\p{IsLatin}]*$");

String[] inputs = { "abcDE 123", "!@#$%^&*", "aaàààäää", "ベビードラ", "????" };
for (String input : inputs) {
    System.out.print("\"" + input + "\": ");
    Matcher matcher = latinPattern.matcher(input);
    if (! matcher.find()) {
        System.out.println("is NON latin");
    } else {
        System.out.println("is latin");
    }
}

输出

"abcDE 123": is latin
"!@#$%^&*": is latin
"aaàààäää": is latin
"ベビードラ": is NON latin
"????": is NON latin

【讨论】:

  • 等等...你确定表情符号不是拉丁语吗?说真的,这个答案很漂亮。
  • @aran 是的,我敢肯定,OP 和 Unicode“脚本”属性也都同意。 ?
  • @aran ? “拉丁大写字母的输入符号” (U+1F520) 不是 "Latin" Script 字符。
【解决方案2】:

所有Latin Unicode character classes 都是:

\p{InBasic_Latin}: U+0000–U+007F
\p{InLatin-1_Supplement}: U+0080–U+00FF
\p{InLatin_Extended-A}: U+0100–U+017F
\p{InLatin_Extended-B}: U+0180–U+024F

所以,答案是要么

Pattern LatinPattern = Pattern.compile("^[\\p{InBasicLatin}\\p{InLatin-1Supplement}\\p{InLatinExtended-A}\\p{InLatinExtended-B}]+$");
Pattern LatinPattern = Pattern.compile("^[\\x00-\\x{024F}]+$"); //U+0000-U+024F

请注意,Java 中的 Unicode 属性类名称中删除了下划线。

Java demo

List<String> strs = Arrays.asList(
        "abcDE 123",  // Yes, this should match
        "!@#$%^&*",   // Yes, this should match
        "aaàààäää",   // Yes, this should match
        "ベビードラ", // No, this shouldn't match
        "????");     // No, this shouldn't match  
Pattern LatinPattern = Pattern.compile("^[\\p{InBasicLatin}\\p{InLatin-1Supplement}\\p{InLatinExtended-A}\\p{InLatinExtended-B}]+$");
//Pattern LatinPattern = Pattern.compile("^[\\x00-\\x{024F}]+$"); //U+0000-U+024F
for (String str : strs) {
    Matcher matcher = LatinPattern.matcher(str);
    if (!matcher.find()) {
        System.out.println(str + " => is NON Latin");
        //return;
    } else {
        System.out.println(str + " => is Latin");
    }
}

注意:如果将.find()替换为.matches(),则可以将模式中的^$丢弃。

输出:

abcDE 123 => is Latin
!@#$%^&* => is Latin
aaàààäää => is Latin
ベビードラ => is NON Latin
???? => is NON Latin

【讨论】:

    猜你喜欢
    • 2018-10-13
    • 2015-02-26
    • 2015-07-09
    • 2018-06-21
    • 2014-12-20
    • 2012-08-16
    • 2018-09-15
    • 1970-01-01
    • 2016-05-13
    相关资源
    最近更新 更多