如何实现Java Collator的数字敏感排序并兼顾国际化?
支持国际化的数字敏感字符串排序方案
当我们对包含数字的字符串列表(比如 {"Test1.txt", "Test2.txt", "Test11.txt", "Test22.txt"})使用 String::compareTo 或默认的 Collator::compare 排序时,会得到不符合人类直观习惯的结果:
Test1.txt Test2.txt Test22.txt Test3.txt
而符合预期的自然排序结果应该是:
Test1.txt Test2.txt Test3.txt Test22.txt
如果不想自己手写数字敏感的比较逻辑,同时还想保留 Collator 自带的国际化排序能力,有以下几种可靠方案:
Java 9+ 自带解决方案
Java 9 开始,Collator 新增了 setNumericCollation(boolean) 方法,直接开启数字敏感排序,同时完全保留原有国际化特性(比如不同语言的字符排序规则)。
示例代码:
import java.text.Collator; import java.util.Arrays; import java.util.List; import java.util.Locale; public class NumericSortExample { public static void main(String[] args) { List<String> files = Arrays.asList("Test1.txt", "Test2.txt", "Test22.txt", "Test3.txt"); // 创建对应Locale的Collator Collator usCollator = Collator.getInstance(Locale.US); // 开启数字敏感排序 usCollator.setNumericCollation(true); // 执行排序 files.sort(usCollator); // 输出结果 files.forEach(System.out::println); } }
运行这段代码就能得到符合预期的自然排序结果,不需要额外依赖。
兼容Java 8及以下的第三方库方案
如果项目还在使用Java 8或更低版本,可以选择以下成熟的第三方库:
ICU4J(推荐)
ICU4J是Unicode官方的Java国际化组件,它的Collator实现比JDK更完善,支持数字敏感排序,同时覆盖更多语言的排序规则。
示例代码:
import com.ibm.icu.text.Collator; import com.ibm.icu.util.ULocale; import java.util.Arrays; import java.util.List; public class ICU4JSortExample { public static void main(String[] args) { List<String> files = Arrays.asList("Test1.txt", "Test2.txt", "Test22.txt", "Test3.txt"); Collator collator = Collator.getInstance(ULocale.US); // 开启数字敏感排序 collator.setNumericCollation(true); files.sort(collator); files.forEach(System.out::println); } }
Apache Commons Lang
可以结合StringUtils的自然排序比较器,不过它的国际化支持不如Collator或ICU4J,适合简单场景:
import org.apache.commons.lang3.StringUtils; import java.util.Arrays; import java.util.List; public class CommonsLangSortExample { public static void main(String[] args) { List<String> files = Arrays.asList("Test1.txt", "Test2.txt", "Test22.txt", "Test3.txt"); files.sort(StringUtils::naturalCompare); files.forEach(System.out::println); } }
参考其他语言实现
比如JavaScript中可以通过Intl.Collator的numeric: true配置快速实现相同功能:
const usCollator = Intl.Collator("us", { numeric: true }); const list = ["Test1.txt", "Test2.txt", "Test3.txt", "Test22.txt"]; list.sort(usCollator.compare); console.log(list);
Java 9+的setNumericCollation就是对标这个特性的官方实现。
内容的提问来源于stack exchange,提问作者Alireza Dastyar
相关产品推荐
相关产品推荐

