1. 概述

在Java中处理String类型时,经常需要分析其中字符的组成。一个常见的任务是计算给定String中的大写和小写字母数量。

在这个教程中,我们将探讨使用Java实现这一功能的一些简单实用的方法。

2. 问题介绍

在深入代码之前,我们先明确一下我们要解决的问题。我们需要创建一个Java方法,它接受一个String作为输入,并同时计数其中的大写和小写字母。换句话说,解决方案将返回包含两个计数器的结果

例如,我们以以下String为例:

static final String MY_STRING = "Hi, Welcome to Baeldung! Let's count letters!";

大写字母是从'A''Z'的字符,小写字母是从'a''z'的字符。也就是说,示例String中的逗号和感叹号等特殊字符不被视为大写或小写字母

根据例子,我们在MY_STRING中有4个大写字母和31个小写字母。

由于我们将同时计算两个计数器,让我们创建一个简单的结果类来携带这两个计数器,以便更容易验证结果:

class LetterCount {
    private int uppercaseCount;
    private int lowercaseCount;
 
    private LetterCount(int uppercaseCount, int lowercaseCount) {
        this.uppercaseCount = uppercaseCount;
        this.lowercaseCount = lowercaseCount;
    }

    public int getUppercaseCount() {
        return uppercaseCount;
    }

    public int getLowercaseCount() {
        return lowercaseCount;
    }
    // ... counting solutions come later ...
}

接下来,我们将把计数解决方案添加到这个类的静态方法中。

因此,如果一种方法正确地计数了字母,它应该产生一个LetterCount对象,其中uppercaseCount = 4lowercaseCount = 31

现在,我们开始计数字母。

3. 使用字符范围

要解决这个问题,我们将遍历给定String中的每个字符,并通过检查它是否落在相应的字符范围内来确定它是大写还是小写字母

static LetterCount countByCharacterRange(String input) {
    int upperCount = 0;
    int lowerCount = 0;
    for (char c : input.toCharArray()) {
        if (c >= 'A' && c <= 'Z') {
            upperCount++;
        }
        if (c >= 'a' && c <= 'z') {
            lowerCount++;
        }
    }
    return new LetterCount(upperCount, lowerCount);
}

如上所示,我们为大写和小写字母维护单独的计数器,并在迭代过程中相应地增加它们。遍历完输入String后,我们使用这两个计数器创建LetterCount对象并将其作为结果返回:

LetterCount result = LetterCount.countByCharacterRange(MY_STRING);
assertEquals(4, result.getUppercaseCount());
assertEquals(31, result.getLowercaseCount());

值得注意的是,这种方法仅适用于由ASCII字符组成的String输入

4. 使用isUpperCase()isLowerCase()方法

在前一个解决方案中,我们通过检查其范围来确定一个字符是大写还是小写字母。实际上,**Character类提供了isUpperCase()isLowerCase()方法来进行这种检查**。

重要的是要注意,isUpperCase()isLowerCase()方法同样适用于Unicode字符:

assertTrue(Character.isLowerCase('ä'));
assertTrue(Character.isUpperCase('Ä'));

因此,我们可以用Character类的字符检查方法替换范围检查:

static LetterCount countByCharacterIsUpperLower(String input) {
    int upperCount = 0;
    int lowerCount = 0;
    for (char c : input.toCharArray()) {
        if (Character.isUpperCase(c)) {
            upperCount++;
        }
        if (Character.isLowerCase(c)) {
            lowerCount++;
        }
    }
    return new LetterCount(upperCount, lowerCount);
}

正如我们所见,这两个字符检查方法使代码更易于理解,并且产生了预期的结果:

LetterCount result = LetterCount.countByCharacterIsUpperLower(MY_STRING);
assertEquals(4, result.getUppercaseCount());
assertEquals(31, result.getLowercaseCount());

5. 使用Stream API的filter()count()方法

Stream API是Java 8中引入的一个重要特性。

接下来,让我们使用Stream API的filter()count()方法来解决这个问题

static LetterCount countByStreamAPI(String input) {
    return new LetterCount(
        (int) input.chars().filter(Character::isUpperCase).count(),
        (int) input.chars().filter(Character::isLowerCase).count()
    );
}

由于count()方法返回一个long值,我们必须将其转换为int来实例化LetterCount对象。

乍一看,这个解决方案可能显得简洁且比其他基于循环的方法更紧凑。然而,值得注意的是,这种方法会两次遍历输入String中的字符

最后,让我们编写一个测试,以确认这种方法是否能得出预期的结果:

LetterCount result = LetterCount.countByStreamAPI(MY_STRING);
assertEquals(4, result.getUppercaseCount());
assertEquals(31, result.getLowercaseCount());

6. 总结

在这篇文章中,我们探讨了在给定String中计算大写和小写字母的不同方法。

这些简单而有效的方法为实际工作中更复杂的String分析任务奠定了基础。

如往常一样,所有示例的完整源代码可在GitHub上找到:https://github.com/eugenp/tutorials/tree/master/core-java-modules/core-java-string-operations-8