Supprimer toutes les occurrences de char de la chaîne


311

Je peux utiliser ceci:

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

Existe-t-il un moyen de supprimer toutes les occurrences de caractère Xd'une chaîne en Java?

J'ai essayé ça et ce n'est pas ce que je veux: str.replace('X',' '); //replace with space


3
Avez-vous essayé de remplacer des chaînes de caractères uniques?
peter.murray.rust

Réponses:


523

Essayez d'utiliser la surcharge qui prend des CharSequencearguments (par exemple, String) plutôt que char:

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

2
Le premier argument est une expression régulière, parfois il ne fonctionnera pas comme prévu, surtout si cette chaîne provient d'une entrée utilisateur.
vbezhenar

9
@vsb: Pas vrai. Les deux arguments de cette surcharge particulière le sont CharSequence. docs.oracle.com/javase/7/docs/api/java/lang/…
LukeH

Que faire en cas Xde type char?
KNU

7
@Kunal: Je suppose que vous en aurez besoin en toStringpremier. Donc, votre code ressemblerait à quelque chosestr = str.replace(yourChar.toString(), "");
LukeH

Notez que vous pouvez utiliser des échappements Unicode, par exemple pas de suppression de non-caractèresstr = str.replace("\uffff", "");
Jaime Hablutzel

42

En utilisant

public String replaceAll(String regex, String replacement)

marchera.

L'utilisation serait str.replace("X", "");.

Exécution

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

Retour:

lakjsdf xx

6
Regex est probablement exagéré pour cela, sauf si vous êtes limité à la prise en charge de Java 1.4 - depuis la version 1.5, il y a une replacesurcharge qui prend un simple CharSequence.
LukeH

3
@LukeH, Ceci est la source décompilée de String.replace. Il utilise regex. Je suis d'accord que le regex semble lourd, mais c'est ce qui est sous le capot même pour la réponse acceptée ci-dessus. public String replace (CharSequence var1, CharSequence var2) {return Pattern.compile (var1.toString (), 16) .matcher (this) .replaceAll (Matcher.quoteReplacement (var2.toString ())); }
Perry Tew

24

Si vous voulez faire quelque chose avec Java Strings, Commons Lang StringUtils est un endroit idéal pour regarder.

StringUtils.remove("TextX Xto modifyX", 'X');

exactement ce que je cherchais, probablement parce que cela semble plus clair que replace.
Ligne

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

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

Ceci est l'exemple pour lequel j'ai supprimé le caractère - de la chaîne.


4
C'est très inefficace, surtout par rapport à la réponse acceptée.
Erick Robertson

3
Je pense que cette réponse fonctionne, mais la bonne réponse est plus courte et plus rapide
evilReiko

2

J'aime utiliser RegEx à cette occasion:

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

où g signifie global donc il passera par toute votre chaîne et remplacera tous les X par ''; si vous voulez remplacer X et x, vous dites simplement:

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

(voir mon violon ici: violon )


Je suppose que cela pourrait fonctionner, mais la bonne réponse s'exécute plus rapidement et plus rapidement, il est toujours préférable d'éviter RegEx autant que possible car il est connu pour être plus lent que les autres méthodes
evilReiko

2

Bonjour Essayez ce code ci-dessous

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

comment feriez-vous si au lieu de x nous avions une autre chaîne? Bonne solution!
Mona Jalal

2

Utilisez replaceAll au lieu de replace

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

Cela devrait vous donner la réponse souhaitée.


replace finit par utiliser replaceAll. Examinez la mise en œuvre. C'est ainsi que String # replace est implémenté: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";donne "deletesalllankstoo"
Kaplan

0

voici une fonction lambda qui supprime tous les caractères passés en chaîne

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"

Cette solution tient compte du fait que la chaîne résultante - à la différence de replace()- ne devient jamais plus grande que la chaîne de départ lors de la suppression de caractères. Ainsi, il évite l'attribution et la copie répétées tout en ajoutant des caractères aux StringBuilderas replace().
Sans parler de la génération inutile Patternet des Matcherinstances replace()qui ne sont jamais nécessaires pour la suppression.
À la différence de replace()cette solution, vous pouvez supprimer plusieurs caractères en un seul coup.


Lambdas / Functional Programming est très branché en ce moment, mais l'utiliser pour créer une solution 10 fois plus longue que la réponse choisie ne peut pas être justifié à mon humble avis, d'où le vote négatif.
Volksman

str.replace("…", "")instancie private Pattern(…)puis sur les appels de modèle générés public String replaceAll(String repl). Les appels de fonction suivants se sont donc produits: return Pattern.compile(target.toString(), Pattern.LITERAL).matcher( this).replaceAll(Matcher.quoteReplacement(replacement.toString())); - voir le commentaire Sal_Vader_808. Dans l'ensemble ca 3 fois plus longtemps que ma solution lambda hip . Et ici, il est bien expliqué pourquoi ma solution hip lambda est également plus rapide: pourquoi String :: replace () de Java est-il si lent?
Kaplan

en propre : s'il s'agissait vraiment de la taille de la solution, d'autres solutions deux fois plus grandes ou les solutions qui nécessitent une bibliothèque externe seraient des candidats plus appropriés pour la critique. Une extension de la langue qui a fait partie de la langue depuis des années depuis Java 8 est pas vraiment branché . Un problème général avec le système de notation est que le facteur temps pèse plus lourd que la qualité d'une solution. En conséquence, les solutions les plus récentes et parfois même meilleures se trouvent de plus en plus dans le tiers arrière.
Kaplan

Je faisais référence à 10 fois plus longtemps en termes de code et non de vitesse d'exécution. Tout ce qui compile un modèle d'expression régulière à chaque fois qu'il est appelé peut être beaucoup plus lent. Vous auriez vraiment besoin de mettre en cache le matcher compilé et de le réutiliser si vous utilisez une telle expression régulière à haute fréquence (OP ne dit pas quel scénario il est utilisé - cela pourrait être un scénario rare pour nettoyer les données d'une soumission de formulaire ou pourrait être utilisé de manière serrée boucle étant appelée des milliers de fois par seconde).
Volksman

En ce qui concerne les problèmes de performance, j'ai ajouté une nouvelle réponse qui permet de comparer rapidement une variété de réponses fournies. Si l'OP effectue cette opération fréquemment, il doit éviter l'option String.replace () car la recompilation répétée du motif d'expression régulière sous le capot est très coûteuse.
Volksman

0

Évaluation des principales réponses avec un repère de performance qui confirme les inquiétudes selon lesquelles la réponse actuellement choisie rend les opérations de regex coûteuses sous le capot

À ce jour, les réponses fournies se déclinent en 3 styles principaux (en ignorant la réponse JavaScript;)):

  • Utilisez String.replace (charsToDelete, ""); qui utilise des regex sous le capot
  • Utilisez Lambda
  • Utilisez une implémentation Java simple

En termes de taille de code, String.replace est clairement le plus laconique. L'implémentation Java simple est légèrement plus petite et plus propre (à mon humble avis) que la Lambda (ne vous méprenez pas - j'utilise souvent Lambdas là où elles sont appropriées)

La vitesse d'exécution était, dans l'ordre du plus rapide au plus lent: implémentation Java simple, Lambda puis String.replace () (qui invoque l'expression régulière).

De loin, l'implémentation la plus rapide a été l'implémentation Java simple, réglée de manière à préallouer le tampon StringBuilder à la longueur de résultat maximale possible, puis à simplement ajouter des caractères au tampon qui ne se trouvent pas dans la chaîne "caractères à supprimer". Cela évite toute réallocation qui se produirait pour des chaînes de plus de 16 caractères (l'allocation par défaut pour StringBuilder) et cela évite le hit de performance "slide left" de supprimer des caractères d'une copie de la chaîne qui se produit est l'implémentation Lambda.

Le code ci-dessous exécute un test de référence simple, exécutant chaque implémentation 1 000 000 fois et enregistre le temps écoulé.

Les résultats exacts varient à chaque exécution, mais l'ordre des performances ne change jamais:

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

L'implémentation Lambda (telle que copiée à partir de la réponse de Kaplan) peut être plus lente car elle effectue un "décalage à gauche d'un" de tous les caractères à droite du caractère supprimé. Cela empirerait évidemment pour les chaînes plus longues avec beaucoup de caractères à supprimer. Il peut également y avoir des frais généraux dans l'implémentation de Lambda elle-même.

L'implémentation String.replace utilise regex et effectue une "compilation" regex à chaque appel. Une optimisation de ceci serait d'utiliser directement l'expression régulière et de mettre en cache le modèle compilé pour éviter le coût de le compiler à chaque fois.

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

Si la fonction lambda est appelée comme elle est censée le faire, le timing est le suivant (personne n'encapsule une fonction lambda dans une fonction membre) . De plus, votre deleteCharsReplace () est incorrectement implémenté: il remplace une chaîne "XYZ" et non pas comme requis 'X', 'Y' et 'Z' ce qui fromString.replace("X", "").replace("Y", "").replace("Z", "");aurait besoin. Nous obtenons maintenant le bon timing: Début simple Time: 759 | Début lambda Heure: 1092 | Démarrer deleteCharsLambda () Heure: 1420 | Début de remplacement corrigé Heure: 4636
Kaplan

"personne n'encapsule une fonction lambda dans une fonction membre" - sauf dans le but de l'appeler dans un scénario de référence afin qu'elle soit cohérente avec la façon dont les autres implémentations sont appelées.
Volksman

Je viens de réaliser que l'OP a demandé de supprimer toutes les occurrences d'un seul caractère, mais votre réponse a changé la portée pour traiter un ensemble de caractères. L'implémentation de réponse "acceptée" que j'ai utilisée n'a pas et n'a jamais été conçue pour prendre en charge plusieurs caractères. J'ai donc mis à jour l'indice de référence ci-dessus pour refléter cela et les temps de référence. BTW si vous souhaitez augmenter la portée pour prendre en charge plusieurs caractères appelant remplacer plusieurs fois est coûteux. Mieux vaut passer à un seul appel pour replaceAll ("[XYZ]", "")
Volksman

La fonction telle qu'indiquée dans la solution n'est modifiée qu'une seule fois lorsqu'elle est appelée. Envelopper la définition de fonction en plus de l'appel de fonction dans la fonction membre a le seul effet de déformer la référence.
Kaplan

Il est pratiquement impossible de comparer correctement les méthodes de durée rapide en effectuant un seul appel car la variance de chaque appel est si élevée. Le benchmarking implique donc normalement de nombreux appels répétés à la même méthode, puis le temps total est évalué pour le comparer avec le temps total des alternatives (ou pour calculer une moyenne si nécessaire).
Volksman

0

Vous devrez mettre les caractères à supprimer entre crochets pendant le temps de remplacement. L'exemple de code sera le suivant:

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

-3

Vous pouvez utiliser str = str.replace("X", "");comme mentionné précédemment et tout ira bien. Car votre information ''n'est pas un caractère vide (ou valide) mais l' '\0'est.

Vous pouvez donc utiliser à la str = str.replace('X', '\0');place.


9
Ceci est une erreur. '\ 0' produira un caractère nul réel. str.replace ('X', '\ 0') est équivalent à str.replace ("X", "\ u0000") qui n'est pas du tout ce que l'OP voulait
Andrey
En utilisant notre site, vous reconnaissez avoir lu et compris notre politique liée aux cookies et notre politique de confidentialité.
Licensed under cc by-sa 3.0 with attribution required.