如何替换除某个特定字符之外的所有字符?

时间:2014-08-06 00:24:29

标签: java

如果我有一个像telephone这样的字符串,并希望输出返回tel*phon*,我该怎么做?

程序会打印出字符串中的每个字母。如果这封信第一次出现,那我就写了。但如果再次出现,我会打印一个星号。

hello将为hel*o

goodbye将为go*dbye

coordination将为co*rdinat***

请帮助谢谢!这不是功课......这是最后的实践!谢谢!

我正在尝试这样的事情......但我只是不知道如何进一步......请帮助

import java.util.Scanner;
public class firstOccurrence{ 
   public static void main(String[] args){
      Scanner keyboard = new Scanner(System.in);
      String s;
      int i, j, count;
      System.out.print("Enter string: ");
      s = keyboard.nextLine();



      for(i = 0; i < s.length(); i++){
         count = 0;
         for(j = i+1; i < s.length(); j++){
            if(s.charAt(i) == s.charAt(j))
               count++;
         }

         if(count < 1)
            System.out.print(s.charAt(i));
         else
            System.out.print("*");
      }
   }
}

如何编辑此确切代码以使其正常工作?请帮忙:(

3 个答案:

答案 0 :(得分:2)

Scanner keyboard = new Scanner(System.in);

String s;
System.out.print("Enter string: ");

s = keyboard.nextLine();

Set<Character> occur=new HashSet<Character>();

StringBuilder stb=new StringBuilder();

for(int i=0;i<s.length();i++){

    if(occur.contains(s.charAt(i)))
        stb.append("*");
    else
        stb.append(s.charAt(i));

    occur.add(s.charAt(i));         

}

System.out.println(stb.toString());

使用本规范,由于两个原因,它更加得体:

  • 使用StringBuilder,因为您的String是可变的
  • 使用set添加唯一元素字符

PS:代码已经过测试

答案 1 :(得分:0)

another answer给出了解决这个问题的简单方法。它迭代输入字符串的每个字符,并构建一组到目前为止看到的字符,使用当前字符构建输出StringBuilder,或者如果已经看到当前字符则替换它。

这个问题似乎应该适合Java 8流处理。有一个新功能String.chars()可将String转换为Stream char。 (但是没有CharStream,因此每个char都表示为int,流类型为IntStream

为此,我们要编写一个mapper函数,该函数可能会替换带有替换字符的字符,但前提是该字符已被查看过。因此,我们需要一个有状态映射器函数,这有点不寻常。但是,使用高阶函数编写一个函数并不困难:

public static IntUnaryOperator replaceIfSeen(int replacement) {
    Map<Integer,Boolean> seen = new ConcurrentHashMap<>();
    return i -> seen.putIfAbsent(i, Boolean.TRUE) == null ? i : replacement;
}

处理基本相同,只是它的包装方式不同。 replaceIfSeen函数返回一个映射器函数,用于在地图中构建所看到的字符。 (没有ConcurrentHashSet因此我们使用地图,但它基本相同。)如果第一次遇到输入字符,则mapper函数返回输入字符,如果已经遇到替换字符,则返回替换字符。它的使用方式如下:

static String replace(String input) {
    return input.chars()
        .map(replaceIfSeen('*'))
        .mapToObj(i -> String.valueOf((char)i))
        .collect(joining());
}

我们获取输入字符串并将其转换为char流(表示为int)并在其上调用我们的条件映射器函数,要求它用*字符替换重复项。 mapToObj操作有点皱纹,因为我们需要将char的{​​{1}}部分转换为单字符字符串。然后我们收集并将这些单字符串连接到输出中。结果如OP所预期的那样。

请注意,如果流并行运行,则行为会有所不同。它仍然有效,因为任何给定字符只出现一次,其他所有字符都被int替换。不同之处在于未替换的角色可能不是第一个。例如,给定输入字符串*,结果可能是coordination

答案 2 :(得分:0)

这是一个正则表达式方法来解决这个问题,一个可以在不使用任何外部容器来跟踪替换的情况下工作的问题:

String s = "coordination";
while(s.matches(".*?(\\w)(?=.*?\\1).*")) {
    s = s.replaceAll("(?<=(\\w))((?:(?!\\1).)*)\\1", "$2*");
}
System.out.println( s );
//=> co*rdinat***

RegEx Demo

<强>解释

  • 虽然循环用于重复替换,只要有多个重复的字符。
  • 此正则表达式使用零宽度lookbehind 来捕获第一个捕获的组(?<=(\\w))中的字母。
  • ((?:(?!\\1).)*)将匹配除第一个捕获的字母之外的所有字符
  • \\1匹配组#1
  • 中下次出现的捕获字母
  • 有关此正则表达式的模式详细信息,请参阅regex101
  • 上提供的演示链接