Entfernen Sie alle Vorkommen von char aus der Zeichenfolge

311

Ich kann das benutzen:

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

Gibt es eine Möglichkeit, alle Vorkommen von Zeichen Xaus einem String in Java zu entfernen ?

Ich habe es versucht und ist nicht das, was ich will: str.replace('X',' '); //replace with space

böseReiko
quelle
3
Haben Sie versucht, einzelne Zeichenfolgen zu ersetzen?
Peter.murray.rust

Antworten:

523

Versuchen Sie, die Überladung zu verwenden, die CharSequenceArgumente (z. B. String) akzeptiert , anstatt char:

str = str.replace("X", "");
LukeH
quelle
2
Das erste Argument ist ein regulärer Ausdruck. Manchmal funktioniert er nicht wie erwartet, insbesondere wenn diese Zeichenfolge aus Benutzereingaben stammt.
Vbezhenar
9
@vsb: Nicht wahr. Beide Argumente dieser besonderen Überlastung sind CharSequence. docs.oracle.com/javase/7/docs/api/java/lang/…
LukeH
Was tun, wenn der XTyp char ist?
KNU
7
@Kunal: Ich denke, du müsstest toStringes zuerst brauchen . Ihr Code würde also str = str.replace(yourChar.toString(), "");
ungefähr
Beachten Sie, dass Sie Unicode-Escapezeichen verwenden können, z. B. keine Nicht- str = str.replace("\uffff", "");
Zeichen
42

Verwenden von

public String replaceAll(String regex, String replacement)

wird funktionieren.

Verwendung wäre str.replace("X", "");.

Ausführen

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

kehrt zurück:

lakjsdf xx
Michael Wiles
quelle
6
Regex ist wahrscheinlich ein Overkill dafür, es sei denn, Sie unterstützen nur Java 1.4 - seit Version 1.5 gibt es eine replaceÜberlastung, die einfach ist CharSequence.
LukeH
3
@LukeH, Dies ist die dekompilierte Quelle für String.replace. Es verwendet Regex. Ich bin damit einverstanden, dass sich Regex schwer anfühlt, aber das ist es, was selbst für die oben akzeptierte Antwort unter der Haube liegt. public String replace (CharSequence var1, CharSequence var2) {return Pattern.compile (var1.toString (), 16) .matcher (this) .replaceAll (Matcher.quoteReplacement (var2.toString ())); }
Perry Tew
24

Wenn Sie etwas mit Java Strings tun möchten, ist Commons Lang StringUtils ein großartiger Ort, um nachzuschauen .

StringUtils.remove("TextX Xto modifyX", 'X');
Arend v. Reinersdorff
quelle
genau das, wonach ich gesucht habe, wahrscheinlich weil es klarer aussieht als replace.
Linie
6
String test = "09-09-2012";
String arr [] = test.split("-");
String ans = "";

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

Dies ist das Beispiel, in dem ich das Zeichen aus dem String entfernt habe.

JavaChamp
quelle
4
Dies ist sehr ineffizient, insbesondere im Vergleich zur akzeptierten Antwort.
Erick Robertson
3
Ich denke, diese Antwort funktioniert, aber die richtige Antwort ist kürzer und schneller
evilReiko
2

Ich benutze RegEx bei dieser Gelegenheit gerne:

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

Dabei bedeutet g global, sodass es Ihre gesamte Zeichenfolge durchläuft und alle X durch '' ersetzt. Wenn Sie sowohl X als auch x ersetzen möchten, sagen Sie einfach:

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

(siehe meine Geige hier: Geige )

Gerrit B.
quelle
Ich denke, das könnte funktionieren, aber die richtige Antwort wird schneller und kürzer ausgeführt. Es ist immer besser, RegEx so weit wie möglich zu vermeiden, da bekannt ist, dass es langsamer ist als andere Methoden
evilReiko
2

Hallo Versuchen Sie diesen Code unten

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();
    }
}
Raju
quelle
Wie würden Sie das tun, wenn wir anstelle von x eine andere Zeichenfolge hätten? Schöne Lösung!
Mona Jalal
2

Verwenden Sie replaceAll anstelle von replace

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

Dies sollte Ihnen die gewünschte Antwort geben.

Ayushi Jain
quelle
Ersetzen endet mit replaceAll. Schauen Sie sich die Implementierung an. So wird String # replace implementiert: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);
        }
    }
}
harikrishna tekkam
quelle
input = "deletes all blanks too";gibt "deletesalllankstoo"
Kaplan
0

Hier ist eine Lambda-Funktion, die alle als Zeichenfolge übergebenen Zeichen entfernt

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"

Diese Lösung berücksichtigt, dass die resultierende Zeichenfolge - im Unterschied zu replace()- beim Entfernen von Zeichen niemals größer als die Startzeichenfolge wird. So ist es die wiederholte Aufteilung und Kopieren während das Anhängen Charakter weise auf die vermeidet , StringBuilderwie der replace()Fall ist.
Ganz zu schweigen von der sinnlosen Generierung von Patternund MatcherInstanzen replace(), die zum Entfernen niemals benötigt werden.
Im Gegensatz zu replace()dieser Lösung können mehrere Zeichen auf einen Schlag gelöscht werden.

Kaplan
quelle
Lambdas / Functional Programming ist momentan sehr angesagt, aber es kann meiner Meinung nach nicht gerechtfertigt werden, damit eine Lösung zu erstellen, die 10x länger ist als die gewählte Antwort.
Volksman
str.replace("…", "")instanziiert private Pattern(…)und dann auf die generierten Musteraufrufe public String replaceAll(String repl). Also passierten folgende Funktionsaufrufe: return Pattern.compile(target.toString(), Pattern.LITERAL).matcher( this).replaceAll(Matcher.quoteReplacement(replacement.toString())); - siehe Kommentar Sal_Vader_808. Alles in allem ca. 3 mal länger als meine Hüft- Lambda-Lösung. Und hier wird gut erklärt, warum meine Hüft- Lambda-Lösung auch schneller ist: Warum ist Javas String :: replace () so langsam?
Kaplan
im eigenen Sinne : Wenn es wirklich um die Größe der Lösung ginge, wären einige andere Lösungen, die doppelt so groß sind, oder Lösungen, die eine externe Bibliothek erfordern, geeignetere Kandidaten für Kritik. Eine Spracherweiterung, die seit Jahren Teil der Sprache ist, seit Java 8, ist nicht wirklich angesagt . Ein allgemeines Problem mit dem Bewertungssystem besteht darin, dass der Zeitfaktor schwerer wiegt als die Qualität einer Lösung. Infolgedessen finden sich im hinteren Drittel zunehmend die aktuelleren und manchmal sogar besseren Lösungen.
Kaplan
Ich bezog mich auf 10x länger in Bezug auf Code nicht Ausführungsgeschwindigkeit. Alles, was bei jedem Aufruf ein Regex-Muster erstellt, kann viel langsamer sein. Sie müssten den kompilierten Matcher wirklich zwischenspeichern und wiederverwenden, wenn Sie einen solchen regulären Ausdruck mit hoher Frequenz verwenden (OP gibt nicht an, in welchem ​​Szenario er verwendet wird - möglicherweise ein seltenes Szenario zum Bereinigen von Daten aus einer Formularübermittlung oder in einem engen Rahmen Schleife wird 1000 Mal pro Sekunde aufgerufen).
Volksman
In Bezug auf Leistungsbedenken habe ich eine neue Antwort hinzugefügt, die einen schnellen Benchmark für eine Vielzahl der bereitgestellten Antworten liefert. Wenn das OP diese Operation häufig ausführt, sollte die Option String.replace () vermieden werden, da die wiederholte Neukompilierung des Regex-Musters unter der Haube sehr kostspielig ist.
Volksman
0

Auswertung der Hauptantworten mit einem Leistungsbenchmark, der Bedenken bestätigt, dass die aktuell gewählte Antwort kostspielige Regex-Operationen unter der Haube macht

Bisher gibt es die drei Antworten in drei Hauptstilen (ohne Berücksichtigung der JavaScript-Antwort;)):

  • Verwenden Sie String.replace (charsToDelete, ""); welches Regex unter der Haube verwendet
  • Verwenden Sie Lambda
  • Verwenden Sie eine einfache Java-Implementierung

In Bezug auf die Codegröße ist der String.replace eindeutig der knappste. Die einfache Java-Implementierung ist etwas kleiner und sauberer (IMHO) als die Lambda (verstehen Sie mich nicht falsch - ich verwende Lambdas oft dort, wo sie angemessen sind).

Die Ausführungsgeschwindigkeit war in der Reihenfolge der schnellsten bis langsamsten: einfache Java-Implementierung, Lambda und dann String.replace () (der Regex aufruft).

Die mit Abstand schnellste Implementierung war die einfache Java-Implementierung, die so abgestimmt wurde, dass sie den StringBuilder-Puffer auf die maximal mögliche Ergebnislänge vorbelegt und dann einfach Zeichen an den Puffer anfügt, die nicht in der Zeichenfolge "Zeichen zum Löschen" enthalten sind. Dadurch werden Neuzuweisungen vermieden, die für Zeichenfolgen mit einer Länge von> 16 Zeichen auftreten würden (die Standardzuweisung für StringBuilder), und es wird vermieden, dass beim Löschen von Zeichen aus einer Kopie der Zeichenfolge, die auftritt, die Lambda-Implementierung auftritt.

Der folgende Code führt einen einfachen Benchmark-Test durch, bei dem jede Implementierung 1.000.000 Mal ausgeführt und die verstrichene Zeit protokolliert wird.

Die genauen Ergebnisse variieren mit jedem Lauf, aber die Reihenfolge der Leistung ändert sich nie:

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

Die Lambda-Implementierung (wie aus Kaplans Antwort kopiert) ist möglicherweise langsamer, da sie eine "Verschiebung um eins um eins" aller Zeichen nach rechts von dem zu löschenden Zeichen ausführt. Dies würde sich offensichtlich bei längeren Zeichenfolgen mit vielen zu löschenden Zeichen verschlechtern. Außerdem kann die Lambda-Implementierung selbst einen gewissen Overhead verursachen.

Die String.replace-Implementierung verwendet Regex und führt bei jedem Aufruf eine Regex-Kompilierung durch. Eine Optimierung hierfür wäre, Regex direkt zu verwenden und das kompilierte Muster zwischenzuspeichern, um die Kosten für die Kompilierung jedes Mal zu vermeiden.

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));
    }
}
Volksman
quelle
Wenn die Lambda-Funktion wie vorgesehen aufgerufen wird, ist das Timing wie folgt (niemand packt eine Lambda-Funktion in eine Elementfunktion) . Außerdem ist Ihr deleteCharsReplace () falsch implementiert: Es ersetzt einen String "XYZ" und nicht wie erforderlich 'X', 'Y' und 'Z', was fromString.replace("X", "").replace("Y", "").replace("Z", "");benötigt würde. Jetzt bekommen wir das richtige Timing: Einfach starten Zeit: 759 | Start Lambda Zeit: 1092 | Starten Sie deleteCharsLambda (). Zeit: 1420 | Start ersetzen korrigiert Zeit: 4636
Kaplan
"Niemand verpackt eine Lambda-Funktion in eine Mitgliedsfunktion" - außer zum Zweck, sie in einem Benchmark-Szenario aufzurufen, damit sie mit der Art und Weise übereinstimmt, wie die anderen Implementierungen aufgerufen werden.
Volksman
Ich habe gerade festgestellt, dass das OP nach dem Entfernen aller Vorkommen eines einzelnen Zeichens gefragt hat, aber Ihre Antwort hat den Umfang geändert, um mit einer Reihe von Zeichen umzugehen. Die von mir verwendete "akzeptierte" Antwortimplementierung ist nicht für mehrere Zeichen vorgesehen und sollte diese auch nie berücksichtigen. Daher habe ich den obigen Benchmark aktualisiert, um dies und die Benchmark-Zeiten widerzuspiegeln. Übrigens, wenn Sie den Umfang erweitern möchten, um mehrere Zeichen zu unterstützen, die das Ersetzen mehrmals aufrufen, ist dies kostspielig. Wechseln Sie besser zu einem einzigen Anruf, um All ("[XYZ]", "") zu ersetzen
Volksman
Die in der Lösung gezeigte Funktion wird beim Aufruf nur einmal aktiviert. Das Umschließen der Funktionsdefinition zusätzlich zum Funktionsaufruf in die Elementfunktion hat den einzigen Effekt, der den Benchmark verzerrt.
Kaplan
Es ist praktisch unmöglich, Methoden mit schneller Dauer durch einen einzelnen Anruf richtig zu bewerten, da die Varianz jedes Anrufs so hoch ist. Das Benchmarking beinhaltet normalerweise viele wiederholte Aufrufe derselben Methode, und dann wird die Gesamtzeit ausgewertet, um sie mit den Gesamtzeiten der Alternativen zu vergleichen (oder um bei Bedarf einen Durchschnitt zu berechnen).
Volksman
0

Sie müssen die Zeichen, die während des Austauschs entfernt werden müssen, in die eckigen Klammern setzen. Der Beispielcode lautet wie folgt:

String s = "$116.42".replaceAll("[$]", "");
Chaklader Asfak Arefe
quelle
-3

Sie können str = str.replace("X", "");wie oben erwähnt verwenden und es wird Ihnen gut gehen. Zu Ihrer Information ''ist kein leeres (oder gültiges) Zeichen sondern '\0'.

Sie könnten also str = str.replace('X', '\0');stattdessen verwenden.

Foivos
quelle
9
Das ist falsch. '\ 0' erzeugt ein tatsächliches Nullzeichen. str.replace ('X', '\ 0') entspricht str.replace ("X", "\ u0000"), was überhaupt nicht das ist, was das OP wollte
Andrey