2015-05-11 15 views
10

Ho una stringa costruita da tipi di tastiera utente, quindi potrebbe contenere '\b' caratteri (backspaces).Java regex - cancella caratteri seguiti da b (backspace)

Voglio pulire la stringa, in modo che non contenga i caratteri '\b', così come i caratteri che devono essere cancellati. Per esempio, la stringa:

String str = "\bHellow\b world!!!\b\b\b."; 

deve essere stampato come:

Hello world. 

ho provato un paio di cose con replaceAll, e quello che ho adesso è:

System.out.println(str.replaceAll("^\b+|.\b+", "")); 

che stampa :

Ciao mondo !!.

Il singolo '\b' viene gestito correttamente, ma i multipli di esso vengono ignorati.

Quindi, posso risolverlo con regex di Java?

EDIT:

ho visto this risposta, ma sembra che non si applicano per replaceAll di Java.
Forse mi manca qualcosa con la stringa verbatim ...

+0

Come si stampa questa stringa per ottenere '\ b' in uscita? – anubhava

+0

Console di Eclipse ... ma la passo anche in XML-RPC e fallisce poiché è un carattere XML non valido ... – Elist

+0

Ho appena visto "Hellow world !!!." Sulla mia console Eclipse senza '\ b' che mostra – anubhava

risposta

5

Non può essere fatto in una sola passata a meno che non ci sia un limite pratico al numero di backspaces consecutivi (che non c'è), e c'è una garanzia (che non c'è) che non ci sono " extra "backspaces per cui non esiste un carattere precedente da eliminare.

Questo fa il lavoro (è a soli 2 piccole linee):

while (str.contains("\b")) 
    str = str.replaceAll("^\b+|[^\b]\b", ""); 

Questo gestisce il caso limite di ingresso come "x\b\by" che ha un backspace extra alla partenza, che dovrebbe essere tagliato una volta che i primi uno consuma il x, lasciando solo "y".

+0

Grazie, adotterò questo approccio . Accetterà questa risposta (se nessun altro ha un Regex puro per batterlo ...) – Elist

+1

Basta una semplice soluzione. se l'input è '\ bbbbbHellow \ b world !!! \ b \ b \ b', avrà un risultato' Hello world !!. 'che penso non sia previsto e dovrebbe darci un output di 'bbbbHello world !!. 'invece. Basta rimuovere il quantificatore all'inizio o impostare '\ b' un gruppo. –

+0

@GarisMSuero - Il tuo esempio stampa 'bbbbHello world' come previsto. – Elist

0

Se ho capito bene la domanda, questa è la soluzione alla tua domanda:

String str = "\bHellow\b world!!!\b\b\b."; 
System.out.println(str.replace(".?\\\b", "")); 
+1

Questo non funziona ... – Elist

+0

Non l'hai fatto. Vuole simulare il tasto di cancellazione backspace su ogni '/ b' trovato. –

0

Questo è stato un bel enigma. Penso che si possa utilizzare una regex per rimuovere lo stesso numero di identici caratteri ripetuti e \b s (vale a dire per una particolare stringa di input):

String str = "\bHellow\b world!!!\b\b\b."; 
System.out.println(str.replaceAll("^\b+|(?:([^\b])(?=\\1*+(\\2?+\b)))+\\2", "")); 

Questo è un adattamento di How can we match a^n b^n with Java regex?.

Vedere IDEONE demo, dove ho aggiunto .replace("\b","<B>")); per vedere se ci sono alcuni \b sinistra.

uscita:

Hello world. 

Una soluzione regex sola generica è al di fuori del campo di applicazione regex ... per ora.

+0

La stringa stessa contiene '.', Il modello non è – Elist

+0

Sì, è per questo che l'ho rimosso dal modello. –

+0

Interessante, ma stampa ancora Hellow \ b world. nella mia console – Elist

3

Il problema che si sta tentando di risolvere, non può essere risolto con singolo espressione regolare. Il problema è che la grammatica, che genera la lingua {any_symbol}*{any_symbol}^n{\b}^n (che è il caso speciale del tuo input) non è regular. È necessario memorizzare lo stato da qualche parte (quanti simboli prima di \b e \b ha letto), ma DFA non può farlo (perché DFA non può sapere quanti sequenziali \ b può trovare). Tutte le soluzioni proposte sono solo regex per il tuo caso ("\bHellow\b world!!!\b\b\b.") e possono essere facilmente interrotte con test più complicati.

soluzione più semplice per il vostro caso è il sostituto in coppia ciclo {tutti tranne \ b} {\ b}

UPD: soluzione, proposta da @Bohemian sembra perfettamente corretto:

UPD 2: Sembra che le espressioni regolari di java possano analizzare not only regular languages, ma anche input come {a}^n{b}^n con lookahead ricorsivo, quindi nel caso di java è possibile associare tali gruppi con una singola espressione regolare. Grazie per i commenti @Pshemo e le modifiche a @Elist!

+1

Sospetto che ciò possa essere fatto con espressioni regolari, ma questa espressione regolare sarebbe estremamente illeggibile, quindi sarebbe meglio creare il nostro parser. – Pshemo

+0

Mi riferisco nuovamente all'esempio C# indicato nella mia modifica: http://stackoverflow.com/a/16604714/1609201. C'è un analogo in Java? In caso contrario, qual è la differenza nella funzione Regex tra le due lingue? – Elist

+0

Ora anche con questa espressione regolare di Java: https://stackoverflow.com/questions/3644266/how-can-we-match-an-bn-with-java-regex che parla di a^n b^n? – Pshemo

4

Sembra un lavoro per Stack!

Stack<Character> stack = new Stack<Character>(); 

// for-each character in the string 
for (int i = 0; i < str.length(); i++) { 
    char c = str.charAt(i); 

    // push if it's not a backspace 
    if (c != '\b') { 
     stack.push(c); 
    // else pop if possible 
    } else if (!stack.empty()) { 
     stack.pop(); 
    } 
} 

// convert stack to string 
StringBuilder builder = new StringBuilder(stack.size()); 

for (Character c : stack) { 
    builder.append(c); 
} 

// print it 
System.out.println(builder.toString()); 

Regex, anche se bello, non è adatto a qualsiasi compito. Questo approccio non è così conciso come Bohemian's, ma è più efficiente. L'uso di uno stack è O (n) in ogni caso, mentre un approccio regex come Bohemian's è O (n) nel peggiore dei casi.

+1

Ovviamente, stack è la soluzione definitiva qui, ma cercavo un modo rapido e "in linea" per risolvere questo problema. Ho anche imparato alcuni trucchi di regex ... – Elist

+1

@Luke ed Elist, mi piace questa soluzione, ma quando "sto facendo funzionare le cose", è incredibile quello che puoi fare con regex praticamente senza codice: è un'abilità che vale la pena imparare . E funziona anche bene - sicuro non nanosecondo veloce, ma un tipico richiamo a 'replaceAll()' richiederà solo pochi microsecondi; è "abbastanza veloce" e puoi procedere rapidamente con il resto del codice e rivisitarlo in un secondo momento se devi spremere più prestazioni dalla tua app. – Bohemian

Problemi correlati