Remova todas as ocorrências de char da string

311

Eu posso usar isso:

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

Existe uma maneira de remover todas as ocorrências de caracteres Xde uma String em Java?

Eu tentei isso e não é o que eu quero: str.replace('X',' '); //replace with space

evilReiko
fonte
3
Você já tentou substituir as cadeias de caracteres únicos?
Peter.murray.rust

Respostas:

523

Tente usar a sobrecarga que recebe CharSequenceargumentos (por exemplo, String) em vez de char:

str = str.replace("X", "");
LukeH
fonte
2
O primeiro argumento é expressão regular; às vezes, não funciona como esperado, especialmente se essa sequência vier da entrada do usuário.
vbezhenar
9
@ VSB: Não é verdade. Ambos os argumentos dessa sobrecarga específica são CharSequence. docs.oracle.com/javase/7/docs/api/java/lang/…
LukeH
O que fazer no caso de Xser do tipo char?
KNU
7
@ Kunal: Eu acho que você precisaria toStringprimeiro. Portanto, seu código seria algo parecido comstr = str.replace(yourChar.toString(), "");
LukeH
Note que você pode usar escapes unicode, por exemplo, há noncharacters removastr = str.replace("\uffff", "");
Jaime Hablutzel
42

Usando

public String replaceAll(String regex, String replacement)

vai funcionar.

Uso seria str.replace("X", "");.

Executando

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

retorna:

lakjsdf xx
Michael Wiles
fonte
6
O Regex provavelmente é um exagero para isso, a menos que você esteja restrito ao suporte ao Java 1.4 - desde a versão 1.5, há uma replacesobrecarga que exige um simples CharSequence.
LukeH 01/01
3
@ LucasH, esta é a fonte descompilada para String.replace. Está usando regex. Concordo que o regex parece pesado, mas é isso que está por trás do capô mesmo para a resposta aceita acima. public String replace (CharSequence var1, CharSequence var2) {return Pattern.compile (var1.toString (), 16) .matcher (este) .replaceAll (Matcher.quoteReplacement (var2.toString ())); }
Perry Tew
24

Se você quiser fazer algo com o Java Strings, o Commons Lang StringUtils é um ótimo lugar para procurar.

StringUtils.remove("TextX Xto modifyX", 'X');
Arend v. Reinersdorff
fonte
exatamente o que eu procurei, provavelmente porque parece mais claro do que replace.
Linha
6
String test = "09-09-2012";
String arr [] = test.split("-");
String ans = "";

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

Este é o exemplo de onde eu removi o caractere - da String.

JavaChamp
fonte
4
Isso é muito ineficiente, especialmente em comparação com a resposta aceita.
Erick Robertson
3
Eu acho que esta resposta funciona, mas a resposta correta é mais curto e mais rápido
evilReiko
2

Eu gosto de usar o RegEx nesta ocasião:

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

onde g significa global para que ele passe por toda a sua string e substitua todo X por ''; se você quiser substituir o X e o x, basta dizer:

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

(veja meu violino aqui: violino )

Gerrit B
fonte
Eu acho que este trabalho poder, mas os corretos executa resposta mais rápida e mais curta, é sempre melhor evitar RegEx, tanto quanto possível, como é conhecido por ser mais lento do que outros métodos
evilReiko
2

Olá Experimente este código abaixo

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
fonte
como você faria isso se, em vez de x, tivéssemos outra string? Ótima solução!
Mona Jalal
2

Use replaceAll em vez de replace

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

Isso deve lhe dar a resposta desejada.

Ayushi Jain
fonte
substituir acaba usando replaceAll. Olhe para a implementação. É assim que a string # replace é implementada: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
fonte
input = "deletes all blanks too";dá "deletesalllankstoo"
Kaplan
0

aqui está uma função lambda que remove todos os caracteres passados ​​como string

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"

Essa solução leva em consideração que a String resultante - diferentemente de replace()- nunca se torna maior que a String inicial ao remover caracteres. Portanto, evita a alocação e a cópia repetidas enquanto acrescenta caracteres no modo StringBuildercomo replace()faz.
Sem mencionar a geração inútil Patterne as Matcherinstâncias em replace()que nunca são necessárias para remoção.
Diferentemente replace()desta solução, você pode excluir vários caracteres de uma só vez.

Kaplan
fonte
Neste momento, o Lambdas / Functional Programming é muito atual, mas usá-lo para criar uma solução 10 vezes maior que a resposta escolhida não pode ser justificado pelo IMHO, daí o voto negativo.
Volksman 18/11/19
str.replace("…", "")instancia private Pattern(…)e depois nas chamadas padrão geradas public String replaceAll(String repl). Então, as seguintes chamadas de função aconteceram: return Pattern.compile(target.toString(), Pattern.LITERAL).matcher( this).replaceAll(Matcher.quoteReplacement(replacement.toString())); - veja o comentário Sal_Vader_808. Ao todo, ca três vezes mais que minha solução lambda de quadril . E aqui está bem explicado por que minha solução hip lambda também é mais rápida: Por que o String :: replace () do Java é tão lento?
Kaplan
por si só : se fosse realmente do tamanho da solução, algumas outras soluções com o dobro do tamanho ou as soluções que exigem uma biblioteca externa seriam candidatos mais adequados para críticas. Uma extensão de linguagem que faz parte da linguagem há anos desde que o Java 8 não é realmente popular . Um problema geral com o sistema de pontuação é que o fator tempo pesa mais do que a qualidade de uma solução. Como resultado, as soluções mais atualizadas e às vezes até melhores são cada vez mais encontradas no terço posterior.
Kaplan
Eu estava me referindo a 10x mais em termos de velocidade de execução do código. Tudo o que compila um padrão regex cada vez que é chamado pode ser muito mais lento. Você realmente precisaria armazenar em cache o comparador compilado e reutilizá-lo se estiver usando essa regex em alta frequência (o OP não diz qual cenário é usado - pode ser um cenário raro para limpar dados de um envio de formulário ou pode ser usado de maneira restrita chamado 1000s de vezes por segundo).
Volksman
No que diz respeito às preocupações com o desempenho, adicionei uma nova resposta que executa uma rápida referência em uma variedade de respostas fornecidas. Se o OP estiver fazendo essa operação com frequência, evite a opção String.replace (), pois a recompilação repetida do padrão regex sob o capô é muito cara.
Volksman 19/11/19
0

Avaliação das principais respostas com uma referência de desempenho que confirma preocupações de que a resposta escolhida atual faça operações regex dispendiosas sob o capô

Até o momento, as respostas fornecidas estão em três estilos principais (ignorando a resposta JavaScript;)):

  • Use String.replace (charsToDelete, ""); que usa regex sob o capô
  • Use Lambda
  • Use implementação Java simples

Em termos de tamanho do código, claramente o String.replace é o mais conciso. A implementação Java simples é um pouco menor e mais limpa (IMHO) do que o Lambda (não me interpretem mal - eu uso o Lambdas sempre que apropriado)

A velocidade de execução foi, na ordem do mais rápido para o mais lento: implementação simples de Java, Lambda e String.replace () (que chama regex).

De longe, a implementação mais rápida foi a simples implementação Java ajustada para pré-alocar o buffer StringBuilder ao tamanho máximo possível do resultado e, em seguida, simplesmente anexa caracteres ao buffer que não está na string "chars to delete". Isso evita qualquer realocação que ocorreria para Strings> 16 caracteres de comprimento (a alocação padrão para StringBuilder) e evita o impacto de desempenho "deslizar para a esquerda" ao excluir caracteres de uma cópia da string que ocorre é a implementação do Lambda.

O código abaixo executa um teste de benchmark simples, executando cada implementação 1.000.000 de vezes e registra o tempo decorrido.

Os resultados exatos variam a cada execução, mas a ordem do desempenho nunca muda:

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

A implementação do Lambda (como copiada da resposta da Kaplan) pode ser mais lenta porque executa um "deslocamento deixado por um" de todos os caracteres à direita do caractere sendo excluído. Obviamente, isso pioraria para cadeias mais longas, com muitos caracteres exigindo exclusão. Também pode haver alguma sobrecarga na própria implementação do Lambda.

A implementação String.replace, usa regex e faz uma regex "compilar" a cada chamada. Uma otimização disso seria usar o regex diretamente e armazenar em cache o padrão compilado para evitar o custo de compilá-lo a cada vez.

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
fonte
Se a função lambda for chamada como pretendida, o tempo será o seguinte (ninguém agrupa uma função lambda em uma função membro) . Além disso, o seu deleteCharsReplace () está implementado incorretamente: ele substitui uma String "XYZ" e não é necessário 'X', 'Y' e 'Z' o que fromString.replace("X", "").replace("Y", "").replace("Z", "");seria necessário. Agora, temos o tempo correto: Comece com um tempo simples: 759 | Iniciar lambda Hora: 1092 | Iniciar deleteCharsLambda () Hora: 1420 | Iniciar a substituição corrigida Hora: 4636
Kaplan
"ninguém agrupa uma função lambda em uma função membro" - exceto com o objetivo de chamá-la em um cenário de benchmark para que seja consistente com a maneira como as outras implementações são chamadas.
Volksman
Acabei de perceber que o OP perguntou sobre a remoção de todas as ocorrências de um único caractere, mas sua resposta mudou o escopo para lidar com um conjunto de caracteres. A implementação de resposta "aceita" que eu usei não foi e nunca teve a intenção de atender a vários caracteres. Portanto, atualizei o benchmark acima para refletir esse e os tempos do benchmark. BTW, se você deseja aumentar o escopo para oferecer suporte a vários caracteres que chamam substituir várias vezes, é caro. Melhor mudar para uma única chamada para replaceAll ( "[XYZ]", "")
Volksman
A função mostrada na solução é iniciada apenas uma vez quando chamada. Envolver a função definitivamente adicionalmente à chamada de função na função membro tem o único efeito de distorcer a referência.
Kaplan
É praticamente impossível avaliar adequadamente os métodos de duração rápida, fazendo uma única chamada, pois a variação de cada chamada é muito alta. Então aferição normalmente envolve muitas chamadas repetidas para o mesmo método e, em seguida, o tempo total é avaliado para comparar com tempos totais das alternativas (ou para calcular uma média, se necessário) ..
Volksman
0

Você precisará colocar os caracteres que precisam ser removidos dentro dos colchetes durante o tempo de substituição. O código de exemplo será o seguinte:

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

Você pode usar str = str.replace("X", "");como mencionado anteriormente e ficará bem. Para sua informação, ''não é um caractere vazio (ou válido), mas '\0'é.

Então você pode usar str = str.replace('X', '\0');.

Foivos
fonte
9
isso está incorreto. '\ 0' produzirá um caractere nulo real. str.replace ('X', '\ 0') é equivalente a str.replace ("X", "\ u0000"), que não é exatamente o que o OP queria
Andrey