Usuń wszystkie wystąpienia znaku z łańcucha

311

Mogę użyć tego:

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

Czy istnieje sposób na usunięcie wszystkich wystąpień znaków Xz ciągu znaków w Javie?

Próbowałem tego i nie jest to, czego chcę: str.replace('X',' '); //replace with space

evilReiko
źródło
3
Czy próbowałeś zastąpić ciągi jednoznakowe?
peter.murray.rust

Odpowiedzi:

523

Spróbuj użyć przeciążenia, które pobiera CharSequenceargumenty (np. String), Zamiast char:

str = str.replace("X", "");
Łukasz
źródło
2
Pierwszy argument jest wyrażeniem regularnym, czasem nie będzie działał zgodnie z oczekiwaniami, szczególnie jeśli ten ciąg pochodzi z danych wprowadzonych przez użytkownika.
vbezhenar
9
@vsb: Nieprawda. Oba argumenty tego konkretnego przeciążenia są CharSequence. docs.oracle.com/javase/7/docs/api/java/lang/…
LukeH
Co zrobić, jeśli Xjest typu char?
KNU
7
@ Kunal: Myślę, że najpierw tego potrzebujesz toString. Więc twój kod wyglądałby str = str.replace(yourChar.toString(), "");
mniej więcej
Uwaga: możesz używać znaków ucieczki unicode, np. Nie usuwaj znaków innych niż znakistr = str.replace("\uffff", "");
Jaime Hablutzel
42

Za pomocą

public String replaceAll(String regex, String replacement)

będzie działać.

Wykorzystanie byłoby str.replace("X", "");.

Wykonywanie

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

zwroty:

lakjsdf xx
Michael Wiles
źródło
6
Regex prawdopodobnie przesadza z tym, chyba że jesteś ograniczony do obsługi Java 1.4 - ponieważ w wersji 1.5 występuje replaceprzeciążenie, które wymaga prostej CharSequence.
Łukasza
3
@LukeH, To jest zdekompilowane źródło String.replace. Używa wyrażenia regularnego. Zgadzam się, że regex wydaje się ciężki, ale to jest pod maską nawet dla powyższej zaakceptowanej odpowiedzi. public String replace (CharSequence var1, CharSequence var2) {return Pattern.compile (var1.toString (), 16) .matcher (this) .replaceAll (Matcher.quoteReplacement (var2.toString ())); }
Perry Tew,
24

Jeśli chcesz coś zrobić z Java Strings, Commons Lang StringUtils to świetne miejsce do oglądania.

StringUtils.remove("TextX Xto modifyX", 'X');
Arend przeciwko Reinersdorff
źródło
dokładnie to, czego szukałem, prawdopodobnie dlatego, że po prostu wygląda bardziej wyraźniej niż replace.
Linia
6
String test = "09-09-2012";
String arr [] = test.split("-");
String ans = "";

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

To jest przykład, w którym usunąłem znak - z Ciągu.

JavaChamp
źródło
4
Jest to bardzo nieefektywne, szczególnie w porównaniu z przyjętą odpowiedzią.
Erick Robertson,
3
Myślę, że ta odpowiedź działa, ale poprawna odpowiedź jest krótsza i szybsza
evilReiko
2

Lubię używać RegEx przy tej okazji:

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

gdzie g oznacza globalny, więc przejdzie przez cały ciąg i zastąpi wszystkie X znakiem „”; jeśli chcesz zamienić zarówno X, jak i X, po prostu powiesz:

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

(patrz moje skrzypce tutaj: skrzypce )

Gerrit B.
źródło
Myślę, że to może zadziałać, ale poprawna odpowiedź jest wykonywana szybciej i krócej, zawsze lepiej jest unikać RegEx tak dużo, jak to możliwe, ponieważ wiadomo, że jest wolniejszy niż inne metody
evilReiko 17.09.13
2

Witaj Wypróbuj ten kod poniżej

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
źródło
jak byś to zrobił, gdyby zamiast x mieliśmy inny ciąg? Fajne rozwiązanie!
Mona Jalal,
2

Użyj replaceAll zamiast replace

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

To powinno dać ci pożądaną odpowiedź.

Ayushi Jain
źródło
zamień kończy się za pomocą replaceAll. Spójrz na wdrożenie. W ten sposób implementowany jest ciąg # zamień: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
źródło
input = "deletes all blanks too";daje „deletesalllankstoo”
Kaplan
0

tutaj jest funkcja lambda, która usuwa wszystkie znaki przekazywane jako ciąg znaków

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"

To rozwiązanie bierze pod uwagę, że wynikowy Ciąg - w przeciwieństwie do replace()- nigdy nie staje się większy niż Ciąg początkowy podczas usuwania znaków. Dzięki temu unika się wielokrotnego przydzielania i kopiowania, jednocześnie dodając znaki do znaku StringBuilderas replace().
Nie wspominając już o bezcelowym generowaniu Patterni Matcherwystąpieniach replace(), które nigdy nie są potrzebne do usunięcia.
W odróżnieniu od replace()tego rozwiązania można usunąć kilka znaków za jednym zamachem.

Kaplan
źródło
Programowanie Lambdas / Functional jest teraz bardzo modne, ale użycie go do stworzenia rozwiązania, które jest 10 razy dłuższe niż wybrana odpowiedź, nie może być uzasadnione IMHO, stąd głosowanie negatywne.
Volksman,
str.replace("…", "")private Pattern(…)tworzy wystąpienia, a następnie generowane wywołania wzorca public String replaceAll(String repl). Tak więc miały miejsce następujące wywołania funkcji: return Pattern.compile(target.toString(), Pattern.LITERAL).matcher( this).replaceAll(Matcher.quoteReplacement(replacement.toString())); - patrz komentarz Sal_Vader_808. W sumie około 3 razy dłużej niż w moim rozwiązaniu hip- lambda. I tutaj jest dobrze wyjaśnione, dlaczego moje hip- lambda jest również szybsze: Dlaczego Java :: String :: replace () jest tak wolny?
Kaplan
sam w sobie : gdyby tak naprawdę był rozmiar rozwiązania, niektóre inne rozwiązania dwa razy większe lub rozwiązania wymagające biblioteki zewnętrznej byłyby bardziej odpowiednimi kandydatami do krytyki. Rozszerzenie języka, które jest częścią tego języka od lat, odkąd Java 8 nie jest tak naprawdę modne . Ogólnym problemem związanym z systemem punktacji jest to, że czynnik czasu waży więcej niż jakość rozwiązania. W rezultacie coraz bardziej aktualne, a czasem nawet lepsze rozwiązania znajdują się coraz częściej na trzecim miejscu.
Kaplan
Miałem na myśli 10 razy dłużej, jeśli chodzi o szybkość wykonywania kodu. Wszystko, co kompiluje wzorzec wyrażenia regularnego za każdym razem, gdy jest wywoływane, może być znacznie wolniejsze. Naprawdę musiałbyś buforować skompilowany moduł dopasowywania i użyć go ponownie, jeśli używasz takiego wyrażenia regularnego z dużą częstotliwością (OP nie określa, w jakim scenariuszu jest on używany) - może to być rzadki scenariusz do wyczyszczenia danych ze złożenia formularza lub może być użyty w ciasnym pętla nazywana jest 1000 razy na sekundę).
Volksman,
W odniesieniu do problemów z wydajnością dodałem nową odpowiedź, która prowadzi szybki test porównawczy dla wielu udzielonych odpowiedzi. Jeśli OP często wykonuje tę operację, powinni unikać opcji String.replace (), ponieważ ponowna kompilacja wzoru wyrażenia regularnego pod maską jest bardzo kosztowna.
Volksman,
0

Ocena głównych odpowiedzi za pomocą wskaźnika wydajności, który potwierdza obawy, że obecnie wybrana odpowiedź powoduje, że kosztowne operacje wyrażenia regularnego są pod maską

Do tej pory dostarczone odpowiedzi są dostępne w 3 głównych stylach (ignorując odpowiedź JavaScript;)):

  • Użyj String.replace (charsToDelete, „”); który używa wyrażenia regularnego pod maską
  • Użyj Lambda
  • Użyj prostej implementacji Java

Jeśli chodzi o rozmiar kodu, String.replace jest najbardziej zwięzły. Prosta implementacja Java jest nieco mniejsza i czystsza (IMHO) niż Lambda (nie zrozum mnie źle - często używam Lambdas tam, gdzie są odpowiednie)

Szybkość wykonywania była w kolejności od najszybszej do najwolniejszej: prosta implementacja Java, Lambda, a następnie String.replace () (która wywołuje wyrażenie regularne).

Zdecydowanie najszybszą implementacją była dostrojona prosta implementacja Java, która wstępnie przypisuje bufor StringBuilder do maksymalnej możliwej długości wyniku, a następnie po prostu dołącza znaki do bufora, które nie znajdują się w ciągu „znaków do usunięcia”. Pozwala to uniknąć wszelkich realokacji, które wystąpiłyby dla ciągów o długości> 16 znaków (domyślny przydział dla StringBuilder) i uniknięto trafienia wydajnościowego „przesuń w lewo” usuwania znaków z kopii ciągu znaków, który jest implementacją Lambda.

Poniższy kod uruchamia prosty test porównawczy, uruchamiając każdą implementację 1 000 000 razy i rejestruje upływ czasu.

Dokładne wyniki różnią się przy każdym uruchomieniu, ale kolejność wydajności nigdy się nie zmienia:

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

Implementacja Lambda (skopiowana z odpowiedzi Kaplana) może być wolniejsza, ponieważ wykonuje „przesunięcie w lewo o jeden” spośród wszystkich znaków na prawo od usuwanej postaci. Oczywiście pogorszy się to w przypadku dłuższych ciągów znaków z dużą ilością znaków wymagających usunięcia. Również w samej implementacji Lambda mogą występować pewne koszty ogólne.

Implementacja String.replace używa wyrażenia regularnego i wykonuje „kompilację” wyrażenia regularnego przy każdym wywołaniu. Optymalizacja tego polega na bezpośrednim użyciu wyrażenia regularnego i buforowaniu skompilowanego wzorca, aby uniknąć kosztu kompilacji za każdym razem.

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
źródło
Jeśli funkcja lambda jest wywoływana zgodnie z przeznaczeniem, taktowanie jest następujące (nikt nie zawija funkcji lambda w funkcję elementu członkowskiego) . Co więcej, twoja metoda deleteCharsReplace () jest niepoprawnie zaimplementowana: zastępuje jeden ciąg „XYZ”, a nie zgodnie z wymaganiami „X”, „Y” i „Z”, co fromString.replace("X", "").replace("Y", "").replace("Z", "");byłoby potrzebne. Teraz otrzymujemy właściwy czas: Rozpocznij prosty Czas: 759 | Rozpocznij lambda Czas: 1092 | Rozpocznij usuwanieCharsLambda () Czas: 1420 | Rozpocznij zastępowanie poprawione Czas: 4636
Kaplan
„nikt nie pakuje funkcji lambda w funkcję członka” - z wyjątkiem celu wywołania jej w scenariuszu testowym, aby była spójna ze sposobem wywoływania innych implementacji.
Volksman
Właśnie zdałem sobie sprawę, że PO poprosił o usunięcie wszystkich wystąpień jednego znaku, ale twoja odpowiedź zmieniła zakres, aby poradzić sobie z zestawem znaków. „Zaakceptowana” implementacja odpowiedzi, której użyłem, nie ma i nigdy nie była przeznaczona do obsługi wielu znaków. Zaktualizowałem więc powyższy test, aby odzwierciedlić to i czasy testów. BTW, jeśli chcesz zwiększyć zakres, aby obsługiwać wiele znaków wywoływania wymiany wiele razy, jest kosztowne. Lepiej przełączyć się na pojedyncze wezwanie, aby zastąpić Wszystkie („[XYZ]”, „”)
Volksman,
Funkcja pokazana w rozwiązaniu jest wywoływana tylko raz po wywołaniu. Dodatkowo zawinięcie definicji funkcji w wywołanie funkcji do funkcji członka ma jedyny efekt zniekształcający test porównawczy.
Kaplan
Właściwie nie jest możliwe prawidłowe porównanie metod szybkiego działania przez wykonanie pojedynczego połączenia, ponieważ wariancja każdego połączenia jest tak wysoka. Więc porównywanie zwykle obejmuje wiele powtarzających się połączeń do tej samej metody, a następnie całkowity czas jest analizowany w celu porównania z sumy czasów alternatyw (lub obliczyć średnią jeśli wymagane) ..
Volksman
0

Podczas wymiany musisz umieścić znaki w nawiasach kwadratowych. Przykładowy kod będzie następujący:

String s = "$116.42".replaceAll("[$]", "");
Chaklader Asfak Arefe
źródło
-3

Możesz używać, str = str.replace("X", "");jak wspomniano wcześniej, i wszystko będzie dobrze. Twoja informacja ''nie jest pustym (lub prawidłowym) znakiem, ale '\0'jest.

Więc możesz użyć str = str.replace('X', '\0');zamiast tego.

Foivos
źródło
9
to jest niepoprawne. „\ 0” wytworzy rzeczywisty znak zerowy. str.replace („X”, „\ 0”) jest równoważne str.replace („X”, „\ u0000”), który wcale nie jest tym, czego chciał PO
Andrey