2013-04-02 2 views
5

Допустим, у нас есть строки, как эти из них:Удалить последние повторяющиеся символы из строки

"abcdaaaaefghaaaaaaaaa" 
"012003400000000" 

Я хотел бы, чтобы удалить последние повторяющиеся символы, чтобы получить это:

"abcdaaaaefgh" 
"0120034" 

Есть простой способ сделать это, с регулярным выражением? Я вроде переживает трудные времена с этим и мой код начинают выглядеть как гигантский монстр ...

Некоторые уточнения:

  • Что считается повторяющимся?

    Последовательность не менее символов в конце. Один символ не считается повторенным. Например: в "aaaa", 'a' не считается повторяющимся, но в "baaaa", это так. Поэтому в случае "aaaa" нам не нужно ничего менять для строки. Другой пример: "baa" должен предоставить "b".

  • И для струнных только одного персонажа?

    Строка как "a", в которой у нас есть только символ 'a' должны быть возвращены без каких-либо изменений, то мы должны вернуть "a".

+0

только один символ повторяется? – Sam

+0

Повторяется ли последний символ? – Loamhoof

+0

Нет, последний символ не всегда повторяется. Он может иметь последовательность не менее 2 символов в конце. Один символ не считается повторенным. – 2013-04-02 13:48:09

ответ

3

Я бы не использовать регулярное выражение:

public class Test { 
    public void test() { 
    System.out.println(removeTrailingDupes("abcdaaaaefghaaaaaaaaa")); 
    System.out.println(removeTrailingDupes("012003400000000")); 
    System.out.println(removeTrailingDupes("0120034000000001")); 
    System.out.println(removeTrailingDupes("cc")); 
    System.out.println(removeTrailingDupes("c")); 
    } 

    private String removeTrailingDupes(String s) { 
    // Is there a dupe? 
    int l = s.length(); 
    if (l > 1 && s.charAt(l - 1) == s.charAt(l - 2)) { 
     // Where to cut. 
     int cut = l - 2; 
     // What to cut. 
     char c = s.charAt(cut); 
     while (cut > 0 && s.charAt(cut - 1) == c) { 
     // Cut that one too. 
     cut -= 1; 
     } 
     // Cut off the repeats. 
     return s.substring(0, cut); 
    } 
    // Return it untouched. 
    return s; 
    } 

    public static void main(String args[]) { 
    new Test().test(); 
    } 
} 

Чтобы соответствовать @ «спецификации» JonSkeet в:

Обратите внимание, что это будет только удалить символы, которые дублированы в конце. Это означает, что строки одиночного символа не будут затронуты, но строки двухзнаковых могут стать пустыми, если оба персонажа одинаковы:

"" => "" 
"x" => "x" 
"xx" => "" 
"aaaa" => "" 
"ax" => "ax" 
"abcd" => "abcd" 
"abcdddd" => "abc" 

Интересно, если можно было бы достичь такого уровня контроля в регулярном выражении?

Добавлено в результате ... но Если мы используем это регулярное выражение с aaaa, например, оно ничего не возвращает. Он должен вернуть aaaa. комментарий:

Вместо этого используйте:

private String removeTrailingDupes(String s) { 
    // Is there a dupe? 
    int l = s.length(); 
    if (l > 1 && s.charAt(l - 1) == s.charAt(l - 2)) { 
     // Where to cut. 
     int cut = l - 2; 
     // What to cut. 
     char c = s.charAt(cut); 
     while (cut > 0 && s.charAt(cut - 1) == c) { 
     // Cut that one too. 
     cut -= 1; 
     } 
     // Cut off the repeats. 
     return cut > 0 ? s.substring(0, cut): s; 
    } 
    // Return it untouched. 
    return s; 
    } 

, который имеет контракт:

"" => "" 
"x" => "x" 
"xx" => "xx" 
"aaaa" => "aaaa" 
"ax" => "ax" 
"abcd" => "abcd" 
"abcdddd" => "abc" 
+0

Я принимаю ваш ответ! Ваше редактирование делает именно то, что я хочу, и не похоже на мой ужасный код монстра, спасибо! – 2013-04-02 13:59:24

9

Вы можете использовать replaceAll() вместе с задней ссылкой:

str = str.replaceAll("(.)\\1+$", ""); 

EDIT

Чтобы удовлетворить требование, чтобы вся строка не удаляются, я бы просто добавить проверку затем вместо чрезмерного усложнения регулярного выражения:

public String replaceLastRepeated(String str) { 
    String replaced = str.replaceAll("(.)\\1+$", ""); 
    if (replaced.equals("")) { 
     return str; 
    } 
    return replaced; 
} 
+2

проклятье! Я писал то же самое :) – Eugene

+2

@ Юджин не только вы, во всяком случае +1 для самого быстрого пистолета. – Pshemo

+0

Если мы используем это регулярное выражение с 'aaaa', например, оно ничего не возвращает. Он должен вернуть 'aaaa' – 2013-04-02 13:45:52

0

Заменить (.)\1+$ пустой строкой:

"abcddddd".replaceFirst("(.)\\1+$", ""); // returns abc 
3

Я не думаю, что я хотел бы использовать регулярное выражение для этого:

public static String removeRepeatedLastCharacter(String text) { 
    if (text.length() == 0) { 
     return text; 
    } 
    char lastCharacter = text.charAt(text.length() - 1); 
    // Look backwards through the string until you find anything which isn't 
    // the final character 
    for (int i = text.length() - 2; i >= 0; i--) { 
     if (text.charAt(i) != lastCharacter) { 
      // Add one to *include* index i 
      return text.substring(0, i + 1); 
     } 
    } 
    // Looks like we had a string such as "1111111111111". 
    return ""; 
} 

Лично я считаю, что легче понять, чем регулярное выражение. Это может быть или не быть быстрее - я не хотел бы делать прогноз.

Обратите внимание, что это будет всегда удалить последний символ, независимо от того, повторяется он или нет.Это означает, что одиночные строки символов всегда будет в конечном итоге как пустые строки:

"" => "" 
"x" => "" 
"xx" => "" 
"ax" => "a" 
"abcd" => "abc" 
"abcdddd" => "abc" 
+1

Не уверен, правильно ли вы правильно обработали односимвольный случай и двухсимвольный случай. Протестируйте с помощью «c» и «0120034000000001» для подтверждения. – OldCurmudgeon

+0

@OldCurmudgeon: Один символ в конечном итоге возвращает пустую строку, всегда. Два символа должны быть в порядке - он войдет в цикл for один раз ('i == 0') и вернет' text.substring (0, 1) ', если два символа отличаются. –

+0

Извините - я редактировал свой комментарий. Мы, похоже, не согласны с толкованием. Нет проблем – OldCurmudgeon

0

Это должно сделать трюк:

public class Remover { 
    public static String removeTrailing(String toProcess) 
    { 
     char lastOne = toProcess.charAt(toProcess.length() - 1); 
     return toProcess.replaceAll(lastOne + "+$", ""); 
    } 

    public static void main(String[] args) 
    { 
     String test1 = "abcdaaaaefghaaaaaaaaa"; 
     String test2 = "012003400000000"; 

     System.out.println("Test1 without trail : " + removeTrailing(test1)); 
     System.out.println("Test2 without trail : " + removeTrailing(test2)); 
    } 
} 
Смежные вопросы