登录
推荐 文章 Go 技术 课程 下载 专题 AI
首页 >  文章 >  java教程

Java Collator 怎样设置重音与大小写的比较层级

来源:17golang原创

时间:2026-11-10 08:19:01 190浏览 收藏

做英文姓名或商品名排序时,直接调用 String.compareTo 往往会把大小写、重音符号和语言规则混在一起。Java 的 Collator 适合把这些差异拆开控制:先用目标语言的 Locale 创建实例,再用 setStrength 选择比较层级,必要时用 setDecomposition 处理字符的规范表示。

要点速览
  • PRIMARY 常用于忽略重音和大小写,只比较基础字母差异。
  • SECONDARY 纳入重音,TERTIARY 通常再纳入大小写,但具体含义依赖 Locale。
  • 单次比较用 compare 更直接;同一批字符串反复排序时,可预先生成同一个 Collator 的 CollationKey。

先把比较层级拆成四档

Collator 不是简单的忽略大小写比较器,它按语言环境定义“哪些差异重要”。官方 API 将强度分为四档:PRIMARY 只看基础字母差异;SECONDARY 通常开始区分重音;TERTIARY 通常再区分大小写;IDENTICAL 进一步保留所有差异。这里的“通常”很重要,因为语言规则由 Locale 决定,不能把英文经验硬套到所有语言。

强度常见关注点适合场景
PRIMARY基础字母搜索去重、宽松匹配
SECONDARY基础字母 + 重音需要区分 é 与 e
TERTIARY再加入大小写展示排序、名称排序
IDENTICAL所有可比较差异需要最严格的稳定顺序

用 Locale 和 strength 组合出排序策略

不要先把字符串统一转小写、再手工移除重音。这样容易丢失原文,也无法表达不同语言的排序规则。下面的示例固定使用美国英语 Locale,比较三个包含大小写与重音差异的字符串:

import java.text.Collator;
import java.util.List;
import java.util.Locale;

public class CollatorStrengthDemo {
    public static void main(String[] args) {
        List names = List.of("cafe", "Café", "café");
        Collator collator = Collator.getInstance(Locale.US);
        // PRIMARY 只保留基础字母层级,适合宽松匹配和去重。
        collator.setStrength(Collator.PRIMARY);

        System.out.println(collator.compare(names.get(0), names.get(1)));
        // 这里的零表示两项在当前比较层级下等价。
        collator.setStrength(Collator.TERTIARY);
        System.out.println(collator.compare(names.get(0), names.get(1)));
        // TERTIARY 通常会把大小写或重音差异重新纳入比较。
    }
}

如果业务只要求“用户输入 Cafe 能找到 café”,选择 PRIMARY 比先改写字符串更清晰;如果结果要稳定展示,通常从 TERTIARY 开始试,并用目标 Locale 的实际数据覆盖测试。图片中的层级关系是静态说明图,不是运行截图。

Java Collator 的 Locale、strength 四级比较层和字符串差异关系说明图
图1:Java Collator 比较层级说明图,展示 Locale、strength 与基础字母、重音、大小写差异的静态关系。

把预分解字符交给 decomposition 处理

strength 决定比较时重视哪些差异,decomposition 决定是否拆解字符表示。NO_DECOMPOSITION 速度较快,但不适合所有带重音的语言;CANONICAL_DECOMPOSITION 处理规范分解;遇到全角、半角等兼容表示时,才考虑 FULL_DECOMPOSITION。这不是“越强越好”,而是要和输入数据的实际编码方式匹配。

import java.text.Collator;
import java.util.Locale;

public class DecompositionDemo {
    public static void main(String[] args) {
        Collator collator = Collator.getInstance(Locale.US);
        // 先纳入重音差异,再用规范分解处理组合字符序列。
        collator.setStrength(Collator.SECONDARY);
        collator.setDecomposition(Collator.CANONICAL_DECOMPOSITION);

        String composed = "é";
        String combining = "e\u0301";
        System.out.println(collator.compare(composed, combining));
        // 输出为 0 只说明当前 Locale、强度和分解设置下两者等价。
    }
}

测试时至少准备预组合字符和组合字符两组样本;如果还涉及兼容字符,再单独评估 FULL_DECOMPOSITION 的代价。不要把一个 Locale 下的结果当成所有语言的通用结论。

排序列表时再切换到 CollationKey

一次比较只调用一次 compare 即可。排序列表时,同一个字符串可能被比较多次,这时可以让 Collator 为每项生成 CollationKey,然后排序这些键。键必须由同一个 Collator 生成,不能把不同 Locale 或不同 strength 的键混在一起。

import java.text.Collator;
import java.util.ArrayList;
import java.util.Comparator;
import java.util.List;
import java.util.Locale;

public class CollationKeyDemo {
    public static void main(String[] args) {
        Collator collator = Collator.getInstance(Locale.US);
        // 固定比较策略后再生成键,避免同一列表出现混合规则。
        collator.setStrength(Collator.TERTIARY);
        List names = new ArrayList(List.of("Zoe", "zoë", "Zoë"));

        names.sort(Comparator.comparing(collator::getCollationKey));
        // 排序阶段比较的是同一 Collator 生成的键。
        names.forEach(System.out::println);
    }
}

生成键本身要扫描完整字符串,所以短列表或只比较一次时未必更快;大量重复排序、分页展示或缓存排序结果时,才值得把键缓存起来。图片中的连接关系是结构说明,不代表某次程序的真实输出。

Java CollationKey 从字符串经同一 Collator 生成并进入列表排序的结构关系图
图2:CollationKey 结构说明图,展示字符串、固定规则的 Collator、排序键与列表排序之间的静态关系。

常见问题

为什么设置 PRIMARY 后重音和大小写都可能相等?

因为 PRIMARY 只保留基础字母层级。是否忽略某种差异仍由 Locale 决定,跨语言时应使用目标语言样本测试。

compare 和 CollationKey 应该怎么选?

单次比较或短列表直接用 compare;同一批字符串会被重复比较时,考虑用同一个 Collator 生成键后排序。

多个线程能共享一个 Collator 吗?

官方文档提示默认的 RuleBasedCollator 并发使用可能产生明显竞争。更稳妥的做法是按线程取得独立实例,或在明确测量后设计安全的实例复用策略。

落地时可以先固定 Locale,再根据“是否忽略重音、是否区分大小写、是否处理组合字符”选择 strength 与 decomposition,最后用代表性数据验证排序边界。这样比较策略会留在配置层,而不是散落在字符串预处理代码里。

声明:本文转载于:17golang原创 如有侵犯,请联系study_golang@163.com删除
相关阅读
更多>
最新阅读
更多>
课程推荐
更多>