返回

Java 移除字符串中非元音字母的几种方法

java

从字符串中移除特定字符:以只保留元音字母为例

在使用 Java 编程时,经常会遇到需要处理字符串的情况,有时需要从中删除某些特定字符。例如,用户输入了一个句子,而你只想保留其中的元音字母(a, e, i, o, u)。 如果你尝试用不正确的方式来实现,可能会遇到编译错误或者无法达到预期效果。 咱们一起看看这个问题,并给出几种解决方案。

问题出在哪儿?

先来看看提问者给出的原始代码:

System.out.println("Enter a sentence :");
Scanner sc = new Scanner(System.in);
String sentence = sc.nextLine();
            
for (int i= 0; i < sentence.length(); i ++) {
    char ch = sentence.charAt(i);
    if (ch != 'a' || ch !='e' || ch !='i' || ch != '0' || ch != 'u' ) {
        String sentence_edited = sentence.replace(i,"");
    }
}
System.out.println(sentence_edited);

这段代码尝试通过循环遍历字符串中的每个字符,然后判断它是否不是元音字母。如果是,就尝试用 replace() 方法将其替换为空字符串。 这段代码存在几个问题:

  1. 逻辑错误: if 条件语句的逻辑不对。 即使 ch 是元音字母 'a',ch != 'e' 仍然为 true,导致整个条件为 true,'a' 也会被错误地移除。应该使用 && (AND) 而不是 || (OR)。
  2. replace() 方法误用: replace() 方法的第一个参数是 CharSequence 类型或者char类型,而不是整数索引。传入整数i会导致编译错误。就算这个地方编译通过,也不是删除本字符.
  3. 变量作用域: sentence_edited 变量在 for 循环内部声明,循环结束后无法访问,导致编译错误。
  4. 效率低下: 在循环中反复调用 replace() 会创建多个新的字符串对象,效率低下,尤其是处理长字符串时。
  5. 没有考虑大小写,实际上还需要考虑'A','E','I','O','U'

解决方案

下面介绍几种更好的解决办法,解决以上提出的效率以及错误等问题:

方法一:使用 replaceAll() 和正则表达式

这是最简洁的方法。replaceAll() 方法接受一个正则表达式作为参数,可以一次性替换所有匹配的字符。

  • 原理: 正则表达式 [^aeiouAEIOU] 匹配所有非元音字母(包括大小写)。replaceAll() 方法将所有匹配到的字符替换为空字符串。

  • 代码示例:

    System.out.println("Enter a sentence :");
    Scanner sc = new Scanner(System.in);
    String sentence = sc.nextLine();
    
    String result = sentence.replaceAll("[^aeiouAEIOU]", "");
    System.out.println(result);
    sc.close();
    
  • 更进一步: 如果要处理包含变音符号的元音字母(如 à, è, ï, ö, ü),可以将正则表达式修改为 [^aeiouAEIOUàèìòùÀÈÌÒÙ],或者使用更全面的 Unicode 字符类。

方法二:使用 StringBuilder

如果对性能有更高要求,或者需要更精细的控制,可以使用 StringBuilder

  • 原理: StringBuilder 是可变字符串,可以直接修改其内容,而无需创建新对象。 循环遍历字符串,判断每个字符是否为元音字母,如果是,则将其追加到 StringBuilder 中。

  • 代码示例:

    System.out.println("Enter a sentence :");
    Scanner sc = new Scanner(System.in);
    String sentence = sc.nextLine();
    
    StringBuilder result = new StringBuilder();
    for (char c : sentence.toCharArray()) {
        if ("aeiouAEIOU".indexOf(c) != -1) {
            result.append(c);
        }
    }
    System.out.println(result.toString());
    sc.close();
    
  • 说明: "aeiouAEIOU".indexOf(c) != -1 用来判断字符 c 是否存在于字符串 "aeiouAEIOU" 中。 如果存在,indexOf() 方法返回其索引(大于等于0),否则返回 -1。

方法三:使用 Java 8 Stream API

Java 8 引入了 Stream API,可以更函数式地处理集合和字符串。

  • 原理: 将字符串转换为字符流,过滤出元音字母,然后将剩余的字符连接成字符串。

  • 代码示例:

        System.out.println("Enter a sentence :");
        Scanner sc = new Scanner(System.in);
        String sentence = sc.nextLine();
    
        String result = sentence.chars()
                .mapToObj(c -> (char) c)
                .filter(c -> "aeiouAEIOU".indexOf(c) != -1)
                .map(String::valueOf)
                .collect(Collectors.joining());
    
        System.out.println(result);
        sc.close();
    
  • 进阶
    如果想通过stream的方式,实现方法一的效果,即使用replaceAll,也可以按如下方式进行

    System.out.println("Enter a sentence :");
        Scanner sc = new Scanner(System.in);
        String sentence = sc.nextLine();
     String result = Pattern.compile("[^aeiouAEIOU]")
                .splitAsStream(sentence)
                .collect(Collectors.joining());
    System.out.println(result);
    sc.close();
    

方法四:手动构建新字符串

虽然效率稍低,但这种方法最直观易懂。

  • 原理: 循环遍历原字符串,判断每个字符是否为元音字母。如果是,就将其追加到一个新的空字符串中。

  • 代码示例:

      System.out.println("Enter a sentence :");
      Scanner sc = new Scanner(System.in);
      String sentence = sc.nextLine();
      String vowels = "aeiouAEIOU";
      String result = "";
    
      for (int i = 0; i < sentence.length(); i++) {
          char ch = sentence.charAt(i);
          if (vowels.indexOf(ch) != -1) {
              result += ch;
          }
      }
    
      System.out.println(result);
      sc.close();
    

总结以及最佳实践

以上四种方式都可以删除String中不需要的字符, 只保留元音字母, 如果考虑到性能和简洁性,方法一通常是最好的选择. 使用正则表达式和replaceAll() 方法可以大大简化代码。当然了, StringBuilderStream也可以满足特定场景下的需求.
具体选哪种, 取决于个人偏好, 代码风格, 以及项目要求.