杰瑞科技汇

Java如何用正则表达式匹配中文?

Unicode 编码范围

中文在 Unicode 编码中占据着特定的范围,正则表达式通过匹配这些范围内的字符来实现对中文的识别。

Java如何用正则表达式匹配中文?-图1
(图片来源网络,侵删)

最常用的 Unicode 范围包括:

  1. 基本汉字: \u4e00 - \u9fff

    这是最核心、最常用的范围,包含了绝大多数日常使用的简体和繁体汉字。

  2. 扩展 A 区: \u3400 - \u4dbf

    包含了一些不常用的汉字,例如一些生僻的古字。

  3. 扩展 B-F 区: \u20000 - \u2a6df, \u2a700 - \u2b73f, \u2b740 - \u2b81f, \u2b820 - \u2ceaf, \u2ceb0 - \u2ebef

    包含了更多的生僻、罕见汉字。

    Java如何用正则表达式匹配中文?-图2
    (图片来源网络,侵删)
  4. 兼容汉字: \uf900 - \ufaff

    主要用于兼容旧标准,通常不推荐在匹配中包含。

注意\u4e00 - \u9fff 已经能满足 99% 的场景,如果你的文本中包含罕见的生僻字,才需要考虑扩展区。


匹配纯中文字符串

如果你的目标是整个字符串必须且只能包含中文,可以使用 ^ (字符串开始) 和 (字符串结束) 进行锚定。

正则表达式:

Java如何用正则表达式匹配中文?-图3
(图片来源网络,侵删)
^[\u4e00-\u9fff]+$
  • ^: 匹配字符串的开头。
  • [\u4e00-\u9fff]: 匹配一个在基本汉字范围内的任意字符。
  • 匹配前面的元素一次或多次。
  • 匹配字符串的结尾。

Java 代码示例:

import java.util.regex.Pattern;
import java.util.regex.Matcher;
public class MatchChineseOnly {
    public static void main(String[] args) {
        // 要测试的字符串
        String str1 = "你好世界"; // 纯中文
        String str2 = "Hello 世界"; // 包含英文
        String str3 = "你好,世界!"; // 包含标点符号
        String str4 = ""; // 空字符串
        // 编译正则表达式
        // Pattern.CASE_INSENSITIVE 在这里没有影响,但是一个好习惯
        Pattern pattern = Pattern.compile("^[\u4e00-\u9fff]+$");
        System.out.println("--- 测试匹配纯中文字符串 ---");
        testString(pattern, str1); // 应该匹配
        testString(pattern, str2); // 不匹配
        testString(pattern, str3); // 不匹配
        testString(pattern, str4); // 不匹配
    }
    public static void testString(Pattern pattern, String str) {
        Matcher matcher = pattern.matcher(str);
        if (matcher.matches()) {
            System.out.println("\"" + str + "\" 是一个纯中文字符串。");
        } else {
            System.out.println("\"" + str + "\" 不是一个纯中文字符串。");
        }
    }
}

输出:

--- 测试匹配纯中文字符串 ---
"你好世界" 是一个纯中文字符串。
"Hello 世界" 不是一个纯中文字符串。
"你好,世界!" 不是一个纯中文字符串。
"" 不是一个纯中文字符串。

匹配字符串中的中文字符(更常用)

在大多数情况下,我们只想从一个包含中文、英文、数字、符号的混合字符串中提取出所有的中文

正则表达式:

[\u4e00-\u9fff]+

这个表达式去掉了 ^ 和 ,所以它会匹配字符串中任意位置的、一个或多个连续的中文。

Java 代码示例:

import java.util.regex.Pattern;
import java.util.regex.Matcher;
public class FindChineseInString {
    public static void main(String[] args) {
        String mixedString = "我的邮箱是 test@example.com,联系电话是 138-1234-5678。";
        // 编译正则表达式
        Pattern pattern = Pattern.compile("[\u4e00-\u9fff]+");
        // 创建 Matcher 对象
        Matcher matcher = pattern.matcher(mixedString);
        System.out.println("--- 从混合字符串中提取中文 ---");
        System.out.println("原始字符串: " + mixedString);
        System.out.print("提取出的中文: ");
        // 使用 find() 和 group() 来查找和获取所有匹配项
        while (matcher.find()) {
            // group() 返回最近一次匹配的子序列
            System.out.print(matcher.group() + " ");
        }
        System.out.println(); // 换行
    }
}

输出:

--- 从混合字符串中提取中文 ---
原始字符串: 我的邮箱是 test@example.com,联系电话是 138-1234-5678。
提取出的中文: 我的 邮箱 是 联系电话 是 

包含标点符号和扩展汉字

我们不仅想匹配汉字,还想匹配中文的标点符号(如 )等,这需要将标点符号的 Unicode 范围也加入到字符集中。

正则表达式:

[\u4e00-\u9fff\u3000-\u303f\uff00-\uffef]+
  • \u3000-\u303f: 主要匹配中文全角标点符号(如 )。
  • \uff00-\uffef: 主要匹配半角及全角形式的标点符号(如 )。

Java 代码示例:

import java.util.regex.Pattern;
import java.util.regex.Matcher;
public class MatchChineseWithPunctuation {
    public static void main(String[] args) {
        String complexString = "你好,世界!This is a test. (测试123)";
        // 编译正则表达式,增加了标点符号的范围
        Pattern pattern = Pattern.compile("[\u4e00-\u9fff\u3000-\u303f\uff00-\uffef]+");
        Matcher matcher = pattern.matcher(complexString);
        System.out.println("--- 匹配中文和标点 ---");
        System.out.println("原始字符串: " + complexString);
        System.out.print("匹配结果: ");
        while (matcher.find()) {
            System.out.print("[" + matcher.group() + "] ");
        }
        System.out.println();
    }
}

输出:

--- 匹配中文和标点 ---
原始字符串: 你好,世界!This is a test. (测试123)
匹配结果: [你好,世界!] [(测试)]

注意:上面的标点符号范围可能不够全面,因为中文标点符号非常丰富,你可以根据需要添加更多的 Unicode 范围,一个更全面(但可能也包含一些非标点符号)的常见范围是 [\u4e00-\u9\uffef]


更全面的匹配(包含扩展汉字)

如果需要匹配包含罕见生僻字的文本,可以将扩展区也加入。

正则表达式:

[\u4e00-\u9fff\u3400-\u4dbf\U00020000-\U0002a6df\U0002a700-\U0002b73f\U0002b740-\U0002b81f\U0002b820-\U0002ceaf\U0002ceb0-\U0002ebef]+

注意:在 Java 中,对于 \u 之外的辅助平面(Supplementary Planes)的字符(如 \U00020000),需要使用 \U 并用8位十六进制表示。

Java 代码示例:

import java.util.regex.Pattern;
import java.util.regex.Matcher;
public class MatchAllChinese {
    public static void main(String[] args) {
        // "𠮷" 是一个生僻字,位于扩展B区 (U+20BB7)
        String rareCharString = "𠮷𠮷 你好";
        // 编译包含扩展区的正则表达式
        // 注意:\U 必须使用大写,并且是8位十六进制
        Pattern pattern = Pattern.compile("[\\u4e00-\\u9fff\\u3400-\\u4dbf\\U00020000-\\U0002a6df\\U0002a700-\\U0002b73f\\U0002b740-\\U0002b81f\\U0002b820-\\U0002ceaf\\U0002ceb0-\\U0002ebef]+");
        Matcher matcher = pattern.matcher(rareCharString);
        System.out.println("--- 匹配所有汉字(含扩展区)---");
        System.out.println("原始字符串: " + rareCharString);
        System.out.print("匹配结果: ");
        while (matcher.find()) {
            System.out.print("[" + matcher.group() + "] ");
        }
        System.out.println();
    }
}

输出:

--- 匹配所有汉字(含扩展区)---
原始字符串: 𠮷𠮷 你好
匹配结果: [𠮷𠮷 你好]

注意:处理这些辅助平面的字符时,Java 的 String.length()charAt() 等方法可能会返回意想不到的结果( 的 length() 是2),因为它们在内部被表示为两个 "代理项对"(surrogate pairs),但在正则表达式匹配中,matcher.group() 会正确地返回完整的字符。


总结与最佳实践

场景 正则表达式 说明
匹配纯中文 ^[\u4e00-\u9fff]+$ 字符串从头到尾只能是中文。
提取中文 [\u4e00-\u9fff]+ 最常用,从混合文本中找出所有连续的中文。
中文+标点 [\u4e00-\u9fff\u3000-\u303f\uff00-\uffef]+ 匹配中文和常见的中文标点符号。
所有汉字 [\u4e00-\u9fff\u3400-\u4dbf\U00020000-\U0002ebef]+ 包含基本汉字和所有扩展区的罕见汉字。

建议:

  1. 从简单开始:优先使用 [\u4e00-\u9fff]+,它能解决绝大多数问题。
  2. 明确需求:你的任务是验证整个字符串(用 ^...$)还是提取部分内容(不用锚定)?
  3. 考虑标点:如果需要匹配句子或段落,请务必将标点符号的范围加入。
  4. 性能:对于非常大的文本,复杂的正则表达式(包含很多范围)可能会影响性能,但在一般情况下,这些正则表达式已经足够高效。
分享:
扫描分享到社交APP
上一篇
下一篇