Apache-Commons-Text

Apache-Commons-Text 及其他文本处理库


commons-text

StringsComparator 字符串对比(Myers差分算法)

@Test
public void myersStringDiff() {
    String source = "The quick brxwn fox jmps over thee lazy dog";
    String target = "The quick brown fox jumps over the lazy dog";
    StringsComparator comparator = new StringsComparator(source, target);
    StringBuilder result = new StringBuilder();
    // 使用 CommandVisitor 来处理比较的结果
    comparator.getScript().visit(new CommandVisitor<>() {
        @Override
        public void visitInsertCommand(Character c) {
            result.append("[+").append(c).append("]");
        }
        @Override
        public void visitKeepCommand(Character c) {
            result.append(c);
        }
        @Override
        public void visitDeleteCommand(Character c) {
            result.append("[-").append(c).append("]");
        }
    });
    System.out.println("source: " + source);
    System.out.println("target: " + target);
    System.out.println("diffs:  " + result);
}

结果:

source: The quick brxwn fox jmps over thee lazy dog
target: The quick brown fox jumps over the lazy dog
diffs:  The quick br[+o][-x]wn fox j[+u]mps over the[-e] lazy dog

LevenshteinDistance 编辑距离

编辑距离,又叫 Levenshtein 距离,莱文斯坦距离,是指两个字串之间,由一个转成另一个所需的最少编辑操作次数。

int distance = LevenshteinDistance.getDefaultInstance().apply(str1, str2);

测试计算 1000 对 20-50 随机长度字符串的编辑距离耗时约 55 毫秒。

@Test
public void testEditDistance() {
    int count = 1000;
    long ts = System.currentTimeMillis();
    for (int i = 0; i < count; i++) {
        String str1 = RandomStringUtils.randomAlphanumeric(20, 50);
        String str2 = RandomStringUtils.randomAlphanumeric(20, 50);
        int distance = LevenshteinDistance.getDefaultInstance().apply(str1, str2);
        log.info("edit distance of {} and {} is {}", str1, str2, distance);
    }
    log.info("cal {} edit distance took {} ms", count, System.currentTimeMillis() - ts);
}

结果 cal 1000 edit distance took 55 ms


google/diff-match-patch 字符串对比(Myers差分算法)

google/diff-match-patch https://github.com/google/diff-match-patch Diff Match Patch 是一个高性能的文本处理库,旨在提供强大的算法来对两个字符串做差异(Diff)、匹配(Match)和补丁(Patch)。该项目最初由 Google 开发,并在多个编程语言中实现了相同的 API。

在线演示及diff计算 https://neil.fraser.name/software/diff_match_patch/demos/diff.html

diff-match-patch 基于 Myers 差分算法,Myers 算法由 Eugene W.Myers 在 1986 年发表的论文 《An O(ND) Difference Algorithm and Its Variations》中提出。Git 的 diff 算法就是 Myers 差分算法 An O(ND) Difference Algorithm and Its Variations https://neil.fraser.name/writing/diff/myers.pdf

maven 引入依赖

<dependency>
    <groupId>org.bitbucket.cowwoc</groupId>
    <artifactId>diff-match-patch</artifactId>
    <version>1.2</version>
</dependency>
DiffMatchPatch dmp = new DiffMatchPatch();
LinkedList<DiffMatchPatch.Diff> diffs = dmp.diffMain(source, target);
dmp.diffCleanupMerge(diffs);

dmp.diffCleanupMerge(diffs) 对差异列表进行合并和清理,其核心功能是:

  • 合并相邻的相同类型操作,将连续的 INSERT/DELETE/EQUAL 操作合并为一个操作(例如多个连续的删除合并为一个大的删除区间)
  • 消除无意义的空操作,删除零长度的差异片段,确保每个差异都有实际意义
  • 优化差异语义,使最终输出的差异更符合人类理解的文本变化逻辑(如避免碎片化的字符级差异)

icu4j

unicode-org / icu https://github.com/unicode-org/icu

ICU4J(International Components for Unicode for Java)是一个开源的 Java 类库,专注于提供全面的 Unicode 和全球化(i18n)支持,帮助开发者处理多语言、多区域环境下的文本、日期、数字等数据。

  1. ​Unicode 文本处理​
    • ​字符集转换​​:支持 100+ 字符集与 Unicode 的相互转换(如 UTF-8、GBK、Shift-JIS),基于 IBM 多年积累的字符集数据,覆盖最全面。
    • ​规范化(Normalization)​​:提供 NFC、NFD、NFKC、NFKD 四种 Unicode 规范化形式,确保文本符合 XML 和网络传输标准。
    • ​大小写转换​​:支持语言敏感的大小写转换(如土耳其语 "i" 的特殊处理)。
  2. ​排序与字符串比较(Collation)​
    • 基于 ​​Unicode 排序算法(UCA)​​,实现语言敏感的字符串排序(如中文按拼音/笔画排序、德语变音符号处理)。
    • 性能优于标准 Java Collator,且支持泰语、高棉语等复杂脚本。
  3. ​国际化格式处理​
    • ​日期/时间格式化​​:支持 30+ 历法(伊斯兰历、希伯来历、农历等)和时区计算,提供相对时间格式化(如“2 天前”)。
    • ​数字/货币格式化​​:支持科学计数法、拼写格式(如“一百元整”)、紧凑格式(如“1.2 万”)。
  4. ​高级文本处理​
    • ​文本边界分析​​:精准识别词、句、行边界,适用于自动换行或分词(尤其支持泰语、中文等无空格语言)。
    • ​双向文本(Bidi)​​:处理混合方向文本(如阿拉伯语+英语),确保正确显示。
    • ​正则表达式​​:完全支持 Unicode 属性的正则引擎,性能优于标准 Java 实现。
  5. ​实用工具​
    • ​字符集检测​​:自动识别未标记文本的编码(如文件编码猜测)。
    • ​文本压缩​​:针对 Unicode 文本的高效压缩算法,适用于小字段存储。

中文繁体转简体

@Test
public void testTradToSimp() {
    String src = "显著";
    // 有问题,转换后 『显著』变成了『显着』
    String dst = Transliterator.getInstance("Traditional-Simplified").transliterate(src);
    System.out.println(dst);
}

Opencc4j

https://github.com/houbb/opencc4j

Opencc4j 是专为 Java 平台设计的中文繁简体转换工具库,基于 OpenCC(Open Chinese Convert)项目思想开发。它支持词组级别的精准转换,严格区分“一简对多繁”和“一简对多异”场景,并兼容异体字动态替换。适用于需处理跨区域中文文本的应用(如大陆、台湾、香港地区用词差异)。

  1. ​精准繁简转换​
    • ​词组级转换​​:不仅处理单字,还考虑上下文词组(如“头发”转繁体为“頭髮”,而非“头髮”)。
    • ​地区适配​​:支持中国大陆、台湾地区用词差异(如“鼠标”转台湾用语“滑鼠”)。
    • ​异体字兼容​​:动态替换异体字(如“裏”与“裡”)。
  2. ​分词与判断能力​
    • ​自定义分词​​:用户可实现 Segment 接口,灵活定制分词策略。
    • ​繁简检测​​:
      • 判断字符/字符串是否为简体(isSimple())或繁体(isTraditional())。
      • 检测字符串中是否包含繁/简体(containsSimple(), containsTraditional())。
    • ​列表提取​​:返回字符串中的简体/繁体字词列表(simpleList(), traditionalList())。
  3. ​灵活性与扩展性​
    • ​词库分离​​:转换规则与代码解耦,支持自定义词库导入。
    • ​多平台兼容​​:Windows、Linux、macOS 全平台支持。

使用示例:

// 简体转繁体
String traditional = ZhConverterUtil.toTraditional("生命不息,奋斗不止"); 
// 输出:生命不息,奮鬥不止

// 繁体转简体
String simple = ZhConverterUtil.toSimple("生命不息,奮鬥不止");  
// 输出:生命不息,奋斗不止

// 检测是否为繁体
boolean isTrad = ZhConverterUtil.isTraditional("編"); // true

中文繁体转简体

@Test
public void testTradToSimp() {
    String traditionalText = "显著";
    String simplifiedText = ZhConverterUtil.toSimple(traditionalText);
    System.out.println("原始文本: " + traditionalText);
    System.out.println("转换结果: " + simplifiedText);
}