Rimuovi tutte le occorrenze di char dalla stringa


311

Posso usare questo:

String str = "TextX Xto modifyX";
str = str.replace('X','');//that does not work because there is no such character ''

C'è un modo per rimuovere tutte le occorrenze di carattere Xda una stringa in Java?

Ho provato questo e non è quello che voglio: str.replace('X',' '); //replace with space


3
Hai provato a sostituire le stringhe a carattere singolo?
peter.murray.rust

Risposte:


523

Prova a utilizzare il sovraccarico che accetta CharSequenceargomenti (ad es. String) Anziché char:

str = str.replace("X", "");

2
Il primo argomento è l'espressione regolare, a volte non funziona come previsto, soprattutto se questa stringa proviene dall'input dell'utente.
vbezhenar,

9
@vsb: non vero. Entrambi gli argomenti di quel particolare sovraccarico sono CharSequence. docs.oracle.com/javase/7/docs/api/java/lang/…
Luca

Cosa fare nel caso in cui Xsia di tipo char?
KNU

7
@Kunal: immagino che prima ne avresti bisogno toString. Quindi il tuo codice sarebbe simile astr = str.replace(yourChar.toString(), "");
LukeH

Nota che puoi usare escape unicode, ad es. Non rimuovere caratteri non caratteristr = str.replace("\uffff", "");
Jaime Hablutzel

42

utilizzando

public String replaceAll(String regex, String replacement)

funzionerà.

L'utilizzo sarebbe str.replace("X", "");.

Esecuzione

"Xlakjsdf Xxx".replaceAll("X", "");

ritorna:

lakjsdf xx

6
Regex è probabilmente eccessivo per questo a meno che tu non sia limitato al supporto di Java 1.4 - poiché la versione 1.5 ha un replacesovraccarico che richiede un semplice CharSequence.
Luca

3
@LukeH, questa è la fonte decompilata in String.replace. Sta usando regex. Sono d'accordo sul fatto che regex sia pesante, ma è quello che c'è sotto il cofano anche per la risposta accettata sopra. public String replace (CharSequence var1, CharSequence var2) {return Pattern.compile (var1.toString (), 16) .matcher (this) .replaceAll (Matcher.quoteReplacement (var2.toString ())); }
Perry Tew,


6
String test = "09-09-2012";
String arr [] = test.split("-");
String ans = "";

for(String t : arr)
    ans+=t;

Questo è l'esempio per cui ho rimosso il personaggio - dalla stringa.


4
Questo è molto inefficiente, soprattutto rispetto alla risposta accettata.
Erick Robertson,

3
Penso che questa risposta funzioni, ma la risposta corretta è più breve e più veloce
evilReiko,

2

Mi piace usare RegEx in questa occasione:

str = str.replace(/X/g, '');

dove g significa globale, quindi passerà attraverso l'intera stringa e sostituirà tutte le X con ''; se vuoi sostituire sia X che x, devi semplicemente dire:

str = str.replace(/X|x/g, '');

(vedi il mio violino qui: violino )


Immagino che potrebbe funzionare, ma la risposta corretta viene eseguita più velocemente e più breve, è sempre meglio evitare RegEx il più possibile poiché è noto che è più lento di altri metodi
evilReiko

2

Ciao Prova questo codice qui sotto

public class RemoveCharacter {

    public static void main(String[] args){
        String str = "MXy nameX iXs farXazX";
        char x = 'X';
        System.out.println(removeChr(str,x));
    }

    public static String removeChr(String str, char x){
        StringBuilder strBuilder = new StringBuilder();
        char[] rmString = str.toCharArray();
        for(int i=0; i<rmString.length; i++){
            if(rmString[i] == x){

            } else {
                strBuilder.append(rmString[i]);
            }
        }
        return strBuilder.toString();
    }
}

come faresti se invece di x avessimo un'altra stringa? Bella soluzione!
Mona Jalal,

2

Usa sostituisci invece di sostituisci

str = str.replaceAll("X,"");

Questo dovrebbe darti la risposta desiderata.


sostituire finisce per sostituire tutto. Guarda l'implementazione. Ecco come viene implementato String # sostituto:return Pattern.compile(target.toString(), Pattern.LITERAL).matcher( this).replaceAll(Matcher.quoteReplacement(replacement.toString()));
Sal_Vader_808

0
package com.acn.demo.action;

public class RemoveCharFromString {

    static String input = "";
    public static void main(String[] args) {
        input = "abadbbeb34erterb";
        char token = 'b';
        removeChar(token);
    }

    private static void removeChar(char token) {
        // TODO Auto-generated method stub
        System.out.println(input);
        for (int i=0;i<input.length();i++) {
            if (input.charAt(i) == token) {
            input = input.replace(input.charAt(i), ' ');
                System.out.println("MATCH FOUND");
            }
            input = input.replaceAll(" ", "");
            System.out.println(input);
        }
    }
}

input = "deletes all blanks too";dà "deletesalllankstoo"
Kaplan,

0

ecco una funzione lambda che rimuove tutti i caratteri passati come stringa

BiFunction<String,String,String> deleteChars = (fromString, chars) -> {
  StringBuilder buf = new StringBuilder( fromString );
  IntStream.range( 0, buf.length() ).forEach( i -> {
    while( i < buf.length() && chars.indexOf( buf.charAt( i ) ) >= 0 )
      buf.deleteCharAt( i );
  } );
  return( buf.toString() );
};

String str = "TextX XYto modifyZ";
deleteChars.apply( str, "XYZ" ); // –> "Text to modify"

Questa soluzione tiene conto del fatto che la stringa risultante - in differenza replace()- non diventa mai più grande della stringa iniziale quando si rimuovono i caratteri. In questo modo si evita l'allocazione e la copia ripetute mentre si aggiunge il carattere a StringBuildercome replace()fa.
Per non parlare della generazione Patterne delle Matcheristanze inutili replace()che non sono mai necessarie per la rimozione.
A differenza di replace()questa soluzione è possibile eliminare più caratteri in un colpo solo.


Lambdas / Programmazione funzionale è molto alla moda in questo momento, ma usarlo per creare una soluzione che è 10 volte più lunga della risposta scelta non può essere giustificato IMHO, quindi il voto negativo.
Volksman,

str.replace("…", "")crea istanze private Pattern(…)e quindi sulle chiamate di pattern generate public String replaceAll(String repl). Quindi sono avvenute le seguenti chiamate di funzione: return Pattern.compile(target.toString(), Pattern.LITERAL).matcher( this).replaceAll(Matcher.quoteReplacement(replacement.toString())); - vedi commento Sal_Vader_808. Tutto sommato circa 3 volte più a lungo della mia soluzione lambda dell'anca . E qui è ben spiegato perché la mia soluzione hip lambda è anche più veloce: perché Java String :: replace () è così lento?
Kaplan,

di per sé : se si trattasse davvero delle dimensioni della soluzione, alcune altre soluzioni due volte più grandi o le soluzioni che richiedono una biblioteca esterna sarebbero candidati più adatti alle critiche. Un'estensione del linguaggio che fa parte del linguaggio da anni poiché Java 8 non è davvero alla moda . Un problema generale con il sistema di punteggio è che il fattore tempo pesa più pesantemente della qualità di una soluzione. Di conseguenza, le soluzioni più aggiornate e talvolta persino migliori si trovano sempre più nel terzo posteriore.
Kaplan,

Mi riferivo a 10 volte di più in termini di codice e non di velocità di esecuzione. Tutto ciò che compila un modello regex ogni volta che viene chiamato può essere molto più lento. Avresti davvero bisogno di memorizzare nella cache il matcher compilato e riutilizzarlo se si utilizza tale regex ad alta frequenza (OP non dice quale scenario viene utilizzato - potrebbe essere uno scenario raro per ripulire i dati dall'invio di un modulo o potrebbe essere utilizzato in modo stretto loop chiamato 1000s di volte al secondo).
Volksman,

Per quanto riguarda le prestazioni, ho aggiunto una nuova risposta che esegue un rapido benchmark su una varietà di risposte fornite. Se l'OP esegue questa operazione frequentemente, dovrebbe evitare l'opzione String.replace () poiché la ricompilazione ripetuta del pattern regex sotto il cofano è molto costosa.
Volksman,

0

Valutazione delle risposte principali con un benchmark delle prestazioni che conferma le preoccupazioni che l'attuale risposta scelta comporti costose operazioni regex sotto il cofano

Ad oggi le risposte fornite sono disponibili in 3 stili principali (ignorando la risposta JavaScript;)):

  • Usa String.replace (charsToDelete, ""); che usa regex sotto il cofano
  • Usa Lambda
  • Usa una semplice implementazione Java

In termini di dimensioni del codice, String.replace è chiaramente il più conciso. La semplice implementazione di Java è leggermente più piccola e più pulita (IMHO) rispetto alla Lambda (non fraintendetemi: uso spesso Lambdas dove sono appropriate)

La velocità di esecuzione era, nell'ordine dal più veloce al più lento: semplice implementazione Java, Lambda e poi String.replace () (che invoca regex).

L'implementazione di gran lunga più rapida è stata la semplice implementazione Java messa a punto in modo tale che preallocasse il buffer StringBuilder alla massima lunghezza possibile dei risultati e quindi aggiungesse semplicemente i caratteri al buffer che non si trovano nella stringa "chars to delete". Questo evita qualsiasi riallocazione che si verificherebbe per stringhe> 16 caratteri di lunghezza (l'allocazione predefinita per StringBuilder) ed evita l'hit di prestazioni "slide left" dell'eliminazione di caratteri da una copia della stringa che si verifica è l'implementazione Lambda.

Il codice seguente esegue un semplice test di benchmark, eseguendo ogni implementazione 1.000.000 di volte e registra il tempo trascorso.

I risultati esatti variano ad ogni esecuzione ma l'ordine delle prestazioni non cambia mai:

Start simple Java implementation
Time: 157 ms
Start Lambda implementation
Time: 253 ms
Start String.replace implementation
Time: 634 ms

L'implementazione Lambda (come copiata dalla risposta di Kaplan) potrebbe essere più lenta perché esegue uno "spostamento lasciato da uno" di tutti i caratteri a destra del personaggio che viene eliminato. Ciò peggiorerebbe ovviamente per stringhe più lunghe con molti caratteri che richiedono la cancellazione. Inoltre potrebbe esserci un certo sovraccarico nell'implementazione Lambda stessa.

L'implementazione String.replace, usa regex e fa una regex "compilare" ad ogni chiamata. Un'ottimizzazione di questo sarebbe utilizzare regex direttamente e memorizzare nella cache il modello compilato per evitare il costo di compilarlo ogni volta.

package com.sample;

import java.util.function.BiFunction;
import java.util.stream.IntStream;

public class Main {

    static public String deleteCharsSimple(String fromString, String charsToDelete)
    {
        StringBuilder buf = new StringBuilder(fromString.length()); // Preallocate to max possible result length
        for(int i = 0; i < fromString.length(); i++)
            if (charsToDelete.indexOf(fromString.charAt(i)) < 0)
                buf.append(fromString.charAt(i));   // char not in chars to delete so add it
        return buf.toString();
    }

    static public String deleteCharsLambda(String fromString1, String charsToDelete)
    {
        BiFunction<String, String, String> deleteChars = (fromString, chars) -> {
            StringBuilder buf = new StringBuilder(fromString);
            IntStream.range(0, buf.length()).forEach(i -> {
                while (i < buf.length() && chars.indexOf(buf.charAt(i)) >= 0)
                    buf.deleteCharAt(i);
            });
            return (buf.toString());
        };

        return deleteChars.apply(fromString1, charsToDelete);
    }

    static public String deleteCharsReplace(String fromString, String charsToDelete)
    {
        return fromString.replace(charsToDelete, "");
    }


    public static void main(String[] args)
    {
        String str = "XXXTextX XXto modifyX";
        String charsToDelete = "X";  // Should only be one char as per OP's requirement

        long start, end;

        System.out.println("Start simple");
        start = System.currentTimeMillis();

        for (int i = 0; i < 1000000; i++)
            deleteCharsSimple(str, charsToDelete);

        end = System.currentTimeMillis();
        System.out.println("Time: " + (end - start));

        System.out.println("Start lambda");
        start = System.currentTimeMillis();
        for (int i = 0; i < 1000000; i++)
            deleteCharsLambda(str, charsToDelete);

        end = System.currentTimeMillis();
        System.out.println("Time: " + (end - start));

        System.out.println("Start replace");
        start = System.currentTimeMillis();

        for (int i = 0; i < 1000000; i++)
            deleteCharsReplace(str, charsToDelete);

        end = System.currentTimeMillis();
        System.out.println("Time: " + (end - start));
    }
}

Se la funzione lambda viene chiamata come previsto, il momento è il seguente (nessuno avvolge una funzione lambda in una funzione membro) . Inoltre il tuo deleteCharsReplace () è implementato in modo errato: sostituisce una stringa "XYZ" e non come richiesto "X", "Y" e "Z" fromString.replace("X", "").replace("Y", "").replace("Z", "");. Ora otteniamo il tempismo corretto: Inizia ora semplice: 759 | Avvia lambda Tempo: 1092 | Avvia deleteCharsLambda () Tempo: 1420 | Inizia a sostituire il tempo corretto: 4636
Kaplan

"nessuno racchiude una funzione lambda in una funzione membro" - tranne per lo scopo di chiamarla in uno scenario di riferimento in modo che sia coerente con il modo in cui vengono chiamate le altre implementazioni.
Volksman,

Mi sono appena reso conto che l'OP ha chiesto di rimuovere tutte le occorrenze di un singolo personaggio, ma la tua risposta ha cambiato l'ambito per gestire un set di caratteri. L'implementazione della risposta "accettata" che ho usato non funziona e non è mai stata pensata per soddisfare più personaggi. Quindi ho aggiornato il benchmark sopra per riflettere questo e i tempi di benchmark. A proposito, se si desidera aumentare l'ambito per supportare più caratteri, chiamare sostituire più volte è costoso. Meglio passare a una singola chiamata per sostituire All ("[XYZ]", "")
Volksman

La funzione mostrata nella soluzione viene attivata una sola volta quando viene chiamata. Avvolgere la funzione definiton in aggiunta alla chiamata di funzione nella funzione membro ha il solo effetto di distorcere il benchmark.
Kaplan,

È praticamente impossibile confrontare correttamente i metodi di durata rapida effettuando una singola chiamata poiché la varianza di ciascuna chiamata è così elevata. Quindi il benchmarking normalmente comporta molte chiamate ripetute allo stesso metodo e quindi viene valutato il tempo totale per confrontarlo con i tempi totali delle alternative (o per calcolare una media se necessario) ..
Volksman

0

Dovrai inserire i caratteri che devono essere rimossi tra parentesi quadre durante il periodo di sostituzione. Il codice di esempio sarà il seguente:

String s = "$116.42".replaceAll("[$]", "");

-3

Puoi usare str = str.replace("X", "");come menzionato prima e starai bene. Per tua informazione ''non è un carattere vuoto (o valido) ma lo '\0'è.

Quindi potresti usare str = str.replace('X', '\0');invece.


9
questo non è corretto. '\ 0' produrrà un carattere nullo effettivo. str.replace ('X', '\ 0') equivale a str.replace ("X", "\ u0000") che non è affatto quello che voleva l'OP
Andrey,
Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.