1. 从字符串中移除特殊字符

有时候我们想从一个字符串中去掉所有非字母、非数字的字符,Guava 的 CharMatcher 提供了非常方便的方法。

比如下面这个例子,我们使用 retainFrom() 方法只保留字母和数字:

@Test
public void whenRemoveSpecialCharacters_thenRemoved(){
    String input = "H*el.lo,}12";
    CharMatcher matcher = CharMatcher.javaLetterOrDigit();
    String result = matcher.retainFrom(input);

    assertEquals("Hello12", result);
}

✅ 简单粗暴,一行搞定。

2. 移除非 ASCII 字符

如果你的数据中混入了一些非 ASCII 的字符(比如日文),而你只想保留英文或数字,可以用以下方式:

@Test
public void whenRemoveNonASCIIChars_thenRemoved() {
    String input = "あhello₤";

    String result = CharMatcher.ascii().retainFrom(input);
    assertEquals("hello", result);

    result = CharMatcher.inRange('0', 'z').retainFrom(input);
    assertEquals("hello", result);
}

⚠️ 注意:inRange('0', 'z') 是个取巧但实用的方式,它会保留从 '0''z' 这个范围内的字符。

3. 移除不在指定字符集中的字符

更进一步,我们可以根据特定字符集来过滤字符。比如下面的例子中,我们只保留能被 “cp437” 字符集编码的字符:

@Test
public void whenRemoveCharsNotInCharset_thenRemoved() {
    Charset charset = Charset.forName("cp437");
    CharsetEncoder encoder = charset.newEncoder();

    Predicate<Character> inRange = new Predicate<Character>() {
        @Override
        public boolean apply(Character c) {
            return encoder.canEncode(c);
        }
    };

    String result = CharMatcher.forPredicate(inRange)
                               .retainFrom("helloは");
    assertEquals("hello", result);
}

💡 这里我们借助 CharsetEncoder 构造了一个 Predicate 来判断字符是否可被编码。

4. 校验字符串内容

CharMatcher 也可以用来做字符串校验,非常实用。

  • matchesAllOf():判断字符串中所有字符是否都满足条件
  • matchesNoneOf():判断字符串中没有任何字符满足条件
  • matchesAnyOf():判断字符串中是否有任意字符满足条件

来看个例子:

@Test
public void whenValidateString_thenValid(){
    String input = "hello";

    boolean result = CharMatcher.javaLowerCase().matchesAllOf(input);
    assertTrue(result);

    result = CharMatcher.is('e').matchesAnyOf(input);
    assertTrue(result);

    result = CharMatcher.javaDigit().matchesNoneOf(input);
    assertTrue(result);
}

✅ 对于格式校验、输入验证这种场景,这个 API 真的很香。

5. 字符串修剪(Trim)

虽然 Java 自带的 trim() 只能去除首尾空格,但 CharMatcher 支持按自定义字符进行修剪:

@Test
public void whenTrimString_thenTrimmed() {
    String input = "---hello,,,";

    String result = CharMatcher.is('-').trimLeadingFrom(input);
    assertEquals("hello,,,", result);

    result = CharMatcher.is(',').trimTrailingFrom(input);
    assertEquals("---hello", result);

    result = CharMatcher.anyOf("-,").trimFrom(input);
    assertEquals("hello", result);
}

🔧 常见用法:

  • trimLeadingFrom():修剪开头
  • trimTrailingFrom():修剪结尾
  • trimFrom():修剪两端

6. 字符串压缩(Collapse)

这个功能特别适合处理连续空格或特殊字符的情况,比如把多个空格合并为一个:

@Test
public void whenCollapseFromString_thenCollapsed() {
    String input = "       hel    lo      ";

    String result = CharMatcher.is(' ').collapseFrom(input, '-');
    assertEquals("-hel-lo-", result);

    result = CharMatcher.is(' ').trimAndCollapseFrom(input, '-');
    assertEquals("hel-lo", result);
}

📌 trimAndCollapseFrom() 是个好东西,自动帮你先 trim 再 collapse,省心。

7. 替换字符串中的字符

除了删除、保留,CharMatcher 也可以用来做字符替换:

@Test
public void whenReplaceFromString_thenReplaced() {
    String input = "apple-banana.";

    String result = CharMatcher.anyOf("-.").replaceFrom(input, '!');
    assertEquals("apple!banana!", result);

    result = CharMatcher.is('-').replaceFrom(input, " and ");
    assertEquals("apple and banana.", result);
}

📌 replaceFrom() 支持替换成字符或字符串,非常灵活。

8. 统计字符出现次数

有时候我们需要统计某个字符或某类字符的出现次数,也可以用 CharMatcher 轻松搞定:

@Test
public void whenCountCharInString_thenCorrect() {
    String input = "a, c, z, 1, 2";

    int result = CharMatcher.is(',').countIn(input);
    assertEquals(4, result);

    result = CharMatcher.inRange('a', 'h').countIn(input);
    assertEquals(2, result);
}

📊 用于日志分析、格式校验等场景非常实用。

9. 总结

通过这篇文章,我们介绍了 CharMatcher 的常用方法和实际应用场景。它在字符串处理方面非常强大,而且代码简洁、语义清晰。

如果你经常需要处理字符串的过滤、校验、替换等操作,Guava 的 CharMatcher 是一个非常值得掌握的工具类。

源码地址:GitHub - EugenP Tutorials


原始标题:Guava CharMatcher