2013-04-02 11 views
5

Powiedzmy, że mamy ciąg jak te z nich:Usuń ostatnie powtarzających znaków z ciągu

"abcdaaaaefghaaaaaaaaa" 
"012003400000000" 

Chciałbym usunąć ostatnie powtarzających się znaków, aby uzyskać w ten sposób:

"abcdaaaaefgh" 
"0120034" 

Czy istnieje prosty sposób to zrobić, z regex? ja niby mający ciężkie czasy z tym i mój kod zaczynają wyglądać gigantycznego potwora ...

Niektóre wyjaśnienia:

  • Co jest uważane za powtarzalne?

    Sekwencja co najmniej znaków na końcu. Jedna postać nie jest uważana za powtarzającą się. Na przykład: w "aaaa", 'a' nie jest uważany za powtarzalny, ale w "baaaa" jest. Tak więc w przypadku "aaaa", nie musimy niczego zmieniać na String. Inna instancja: "baa" musi dać "b".

  • A dla łańcuchów tylko jednej postaci?

    Ciąg jak "a" w którym mamy tylko char 'a' musi być zwrócony bez zmieniania czegokolwiek, to musimy powrócić "a".

+0

Tylko jeden znak powtarza? – Sam

+0

Czy ostatni znak jest zawsze powtarzany? – Loamhoof

+0

Nie, ostatnia postać nie zawsze się powtarza. Może zawierać sekwencję co najmniej 2 znaków na końcu. Jedna postać nie jest uważana za powtarzającą się. –

Odpowiedz

3

Nie użyłbym regex:

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(); 
    } 
} 

Aby dopasować @ "SPEC" JonSkeet za:

pamiętać, że będzie tylko usunąć znaki, które są powielone na końcu. Oznacza to, że ciągi znaków nie będzie pojedynczy być dotykana, ale struny dwuznakowego może stać pusty, jeśli obie postacie są takie same:

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

Zastanawiam się, czy byłoby możliwe, aby osiągnąć ten poziom kontroli w regex?

Dodano w wyniku ... ale jeśli użyjemy tego wyrażenia na przykład na aaaa, to nic nie zwraca. Powinno to zwrócić aaaa. komentarz:

Zamiast zastosowanie:

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; 
    } 

który ma umowę:

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

Akceptuję twoją odpowiedź! Twoja edycja robi dokładnie to, czego chcę, i nie wygląda na mój okropny kod potwora, dziękuję! –

9

Można użyć replaceAll() razem z tylnym odniesienia:

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

EDIT

Aby spełnić wymóg, że cały ciąg nie może zostaną usunięte Chciałbym po prostu dodać czek następnie zamiast wykonywania zbyt skomplikowane regex:

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

cholera! Pisałem to samo :) – Eugene

+2

@Eugene nie tylko ty, tak czy inaczej +1 dla najszybszego działa. – Pshemo

+0

Jeśli użyjemy tego wyrażenia z 'aaaa' na przykład, to nic nie zwraca. Powinien zwrócić 'aaaa' –

0

Wymień (.)\1+$ przez pusty ciąg:

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

nie sądzę bym użyć tego wyrażenia regularnego:

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 ""; 
} 

Osobiście Uważam, że łatwiejsze do zrozumienia niż regex. Może, ale nie musi, być szybsze - nie chciałbym przepowiadać.

Pamiętaj, że będzie to zawsze usunąć ostatnią postać, czy to powtórzone, czy nie.Oznacza to, że pojedyncze ciągi znaków będzie zawsze kończy się jako pustych strun:

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

Nie jestem pewien, czy poprawnie załatwiłeś sprawę jednoliterową i dwuznakową. Przetestuj za pomocą "c" i "0120034000000001", aby potwierdzić. – OldCurmudgeon

+0

@ OldCurmudgeon: Pojedyncza postać w końcu zwraca ciąg pusty, zawsze. Dwa znaki powinny być w porządku - przejdzie ono do pętli for raz ('i == 0') i zwróci' text.substring (0, 1) 'jeśli te dwie litery są różne. –

+0

Przepraszam - edytowałem swój komentarz. Wydaje się, że nie zgadzamy się co do interpretacji. Żaden problem – OldCurmudgeon

0

To powinno załatwić sprawę:

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)); 
    } 
} 
Powiązane problemy