【问题标题】:Removing duplicate same characters in a row连续删除重复的相同字符
【发布时间】:2013-04-17 07:42:56
【问题描述】:

我正在尝试创建一种方法,该方法可以从字符串中删除所有重复项,或者根据参数仅在一行中保留相同的 2 个字符。

例如:

helllllllo -> helo

helllllllo -> hello - 这保留了双字母

目前我通过以下方式删除重复项:

private String removeDuplicates(String word) {
    StringBuffer buffer = new StringBuffer();
    for (int i = 0; i < word.length(); i++) {
        char letter = word.charAt(i);
        if (buffer.length() == 0 && letter != buffer.charAt(buffer.length() - 1)) {
            buffer.append(letter);
        }
    }
    return buffer.toString();
}

如果我想保留双字母,我正在考虑使用私有字符串 removeDuplicates(String word, boolean doubleLetter) 之类的方法

doubleLetter 为真时,它将返回hello 而不是helo

我不确定在不复制大量代码的情况下最有效的方法。

【问题讨论】:

  • StringBuilder 可能会好一点
  • 您也可以在 if 循环中简单地增加一个计数器,并添加另一个 if 循环,如果计数器低于阈值,则仅附加该字母 --- 这将是使用任何数字的通用版本重复(但您应该确保在扫描完最后一个字母之外的另一个字母后重新设置计数器)。

标签: java


【解决方案1】:

为什么不直接使用正则表达式?

 public class RemoveDuplicates {
      public static void main(String[] args) {
           System.out.println(new RemoveDuplicates().result("hellllo", false)); //helo
           System.out.println(new RemoveDuplicates().result("hellllo", true)); //hello
      }

      public String result(String input, boolean doubleLetter){
           String pattern = null;
           if(doubleLetter) pattern = "(.)(?=\\1{2})";
           else pattern = "(.)(?=\\1)";
       return input.replaceAll(pattern, "");
      }
 }

 (.)    --> matches any character and puts in group 1. 
 ?=     --> this is called a positive lookahead. 
 ?=\\1  --> positive lookahead for the first group

因此,总的来说,此正则表达式会查找其后面的任何字符(正向前瞻)。例如aa或bb等。需要注意的是实际上只有第一个字符是匹配的一部分,所以在单词'hello'中,只有第一个l被匹配(部分(?=\1)是不是比赛的一部分)。所以第一个 l 被一个空字符串替换,我们留下了 helo,它与正则表达式不匹配

第二个模式是一样的,但这次我们期待第一组的两次出现,例如hello。另一方面,'hello' 将不匹配。

查看更多信息:Regex

附:如果有帮助,请随意填写以接受答案。

【讨论】:

  • 感谢尤金的回答。你能简单地为我解释一下正则表达式吗?
【解决方案2】:

试试

    String s = "helllllllo";
    System.out.println(s.replaceAll("(\\w)\\1+", "$1"));

输出

helo

【讨论】:

    【解决方案3】:

    this 之前的 SO 示例为起点,我想出了这个:

        String str1= "Heelllllllllllooooooooooo";
        
        String removedRepeated = str1.replaceAll("(\\w)\\1+", "$1");
        System.out.println(removedRepeated);
        
        String keepDouble = str1.replaceAll("(\\w)\\1{2,}", "$1");
        System.out.println(keepDouble);
    

    它产生:

    直升机

    鞋跟

    它的作用:

    (\\w)\\1+ 将匹配任何字母并将其放在正则表达式捕获组中。该组稍后可通过\\1+ 访问。这意味着它将匹配上一个字母的一个或多个重复。

    (\\w)\\1{2,} 与上面相同,唯一的区别是它只关注重复超过 2 次的字符。这使双字符保持不变。

    编辑: 重新阅读问题,您似乎想用双打替换多个字符。为此,只需使用以下行:

    String keepDouble = str1.replaceAll("(\\w)\\1+", "$1$1");

    【讨论】:

      【解决方案4】:

      试试这个,这将是最有效的方法[评论后编辑]:

      public static String removeDuplicates(String str) {
          int checker = 0;
          StringBuffer buffer = new StringBuffer();
          for (int i = 0; i < str.length(); ++i) {
              int val = str.charAt(i) - 'a';
              if ((checker & (1 << val)) == 0)
                  buffer.append(str.charAt(i));
              checker |= (1 << val);
          }
          return buffer.toString();
      }
      

      我正在使用位来识别唯一性。

      编辑:

      整个逻辑是,如果一个字符已经被解析,那么它的对应位被设置,下次当该字符出现时,它不会被添加到字符串缓冲区中,对应的位已经被设置。

      【讨论】:

      • buffer.append(val) 行必须替换为buffer.append(str.charAt(i)) 行(参见演示:ideone.com/AtYH8a),并且 'a' 周围的单引号是错误的,用标准的替换它们;)
      • 不客气。请注意,更复杂的输入字符串会出现错误:ideone.com/FmiXEe 应改为提供ideone.com/HvogfI:/ 需要进行一些修复
      • 我没听明白。你能详细说明吗?或者举个例子?
      • 比较输出;也许您要删除该行中多次出现的所有字符,而不是所有字符都加倍...如果是这样,那就很好
      • 我会进一步测试它,但我觉得它会起作用。整个逻辑是,如果一个字符已经被解析,那么它的对应位被设置,下次当这个字符出现时,它就不会被添加到字符串缓冲区中。因此,无论字符串中字符的位置如何,逻辑都应该起作用。
      猜你喜欢
      • 1970-01-01
      • 2015-01-26
      • 1970-01-01
      • 2022-01-12
      • 1970-01-01
      • 2019-09-02
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多