2013-04-02 17 views
5

Diciamo che abbiamo una stringa come questi:Rimuovere ultimi caratteri ripetitivi di una stringa

"abcdaaaaefghaaaaaaaaa" 
"012003400000000" 

Vorrei rimuovere gli ultimi caratteri ripetitivi, per ottenere questo:

"abcdaaaaefgh" 
"0120034" 

C'è un modo semplice per farlo, con regex? Sto sorta di avere tempi duri con questo e il mio codice comincio a guardare come un mostro gigantesco ...

Alcuni chiarimenti:

  • Quello che è considerato come ripetitivo?

    Una sequenza di almeno caratteri alla fine. Un personaggio non è considerato ripetuto. Ad esempio: in "aaaa", 'a' non è considerato ripetitivo, ma in "baaaa", lo è. Pertanto, nel caso di "aaaa", non è necessario modificare nulla nella stringa. Un'altra istanza: "baa" deve fornire "b".

  • E per stringhe di un solo carattere?

    una stringa come "a" in cui è rimasto solo il char 'a' deve essere restituito senza cambiare nulla, cioè dobbiamo tornare "a".

+0

un solo personaggio si ripete? – Sam

+0

L'ultimo carattere è sempre ripetuto? – Loamhoof

+0

No, l'ultimo carattere non viene sempre ripetuto. Può avere una sequenza di almeno 2 caratteri alla fine. Un personaggio non è considerato ripetuto. –

risposta

3

Non vorrei usare un'espressione regolare:

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

Da abbinare @ "spec" del JonSkeet:

Si noti che questo solo rimuovere i caratteri che sono duplicati alla fine. Ciò significa che le stringhe di carattere singolo non saranno toccati, ma le stringhe di due caratteri potrebbero diventare vuota se entrambi i personaggi sono gli stessi:

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

mi chiedo se sarebbe possibile per raggiungere tale livello di controllo in una regex?

Aggiunto come risultato del ... ma Se usiamo questo regex con aaaa per esempio, non restituisce nulla. Dovrebbe tornare aaaa. commento:

Invece, l'uso:

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

che ha il contratto:

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

Accetto la tua risposta! La tua modifica fa esattamente quello che voglio, e non sembra il mio orribile codice mostro, grazie! –

9

È possibile utilizzare replaceAll() insieme ad un riferimento all'indietro:

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

EDIT

per soddisfare il requisito che l'intera stringa non può ottenere rimosso Vorrei semplicemente aggiungere un controllo in seguito invece di rendere eccessivamente complicata la regex:

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

dannazione! Stavo scrivendo la stessa cosa :) – Eugene

+2

@Eugene non solo tu, comunque +1 per la pistola più veloce. – Pshemo

+0

Se usiamo questa regex con 'aaaa' per esempio, non restituisce nulla. Dovrebbe restituire 'aaaa' –

0

Sostituire (.)\1+$ da una stringa vuota:

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

Non credo che mi piacerebbe usare una regex per questo:

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

Personalmente trovo che facile da capire che una regex. Potrebbe essere o non essere più veloce - non vorrei fare una previsione.

Si noti che questo sarà sempre rimuovere il carattere finale, se è ripetuto o meno.Ciò significa che le stringhe di caratteri singoli saranno sempre finire come stringhe vuote:

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

Non sono sicuro se hai gestito correttamente la custodia di un carattere e la custodia di due caratteri correttamente. Test con "c" e con "0120034000000001" per confermare. – OldCurmudgeon

+0

@OldCurmudgeon: un singolo carattere finirà per restituire una stringa vuota, sempre. Due caratteri dovrebbero essere a posto - inserirà il ciclo for una volta ('i == 0') e restituirà' text.substring (0, 1) 'se i due caratteri sono diversi. –

+0

Scusa - Ho modificato il mio commento. Sembra che non siamo d'accordo sull'interpretazione. Nessun problema – OldCurmudgeon

0

Questo dovrebbe fare il trucco:

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)); 
    } 
} 
Problemi correlati