Eliminar todas las apariciones de char de la cadena


311

Puedo usar esto:

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

¿Hay alguna manera de eliminar todas las apariciones de caracteres Xde una Cadena en Java?

Intenté esto y no es lo que quiero: str.replace('X',' '); //replace with space


3
¿Has intentado reemplazar cadenas de caracteres individuales?
peter.murray.rust 01 de

Respuestas:


523

Intente usar la sobrecarga que toma CharSequenceargumentos (por ejemplo, String) en lugar de char:

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

2
El primer argumento es la expresión regular, a veces no funcionará como se esperaba, especialmente si esta cadena proviene de la entrada del usuario.
vbezhenar

99
@vsb: No es cierto. Ambos argumentos de esa sobrecarga en particular son CharSequence. docs.oracle.com/javase/7/docs/api/java/lang/…
LukeH

¿Qué hacer en caso de que Xsea ​​del tipo char?
KNU

77
@Kunal: Creo que lo necesitarías toStringprimero. Entonces su código se vería algo asístr = str.replace(yourChar.toString(), "");
LukeH

Tenga en cuenta que puede usar escapes Unicode, por ejemplo, no eliminar no caracteresstr = str.replace("\uffff", "");
Jaime Hablutzel

42

Utilizando

public String replaceAll(String regex, String replacement)

trabajará.

El uso sería str.replace("X", "");.

Ejecutando

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

devoluciones:

lakjsdf xx

66
Regex probablemente sea excesivo para esto, a menos que esté restringido a admitir Java 1.4, ya que la versión 1.5 tiene una replacesobrecarga que toma un simple CharSequence.
LukeH

3
@LukeH, esta es la fuente descompilada para String.replace. Está usando expresiones regulares. Estoy de acuerdo en que regex se siente pesado, pero eso es lo que está debajo del capó incluso para la respuesta aceptada anteriormente. 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;

Este es el ejemplo de donde he eliminado el personaje: de la cadena.


44
Esto es muy ineficiente, especialmente en comparación con la respuesta aceptada.
Erick Robertson

3
Creo que esta respuesta funciona, pero la respuesta correcta es más corto y más rápido
evilReiko

2

Me gusta usar RegEx en esta ocasión:

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

donde g significa global, por lo que pasará por toda la cadena y reemplazará todas las X con '' Si desea reemplazar X y X, simplemente diga:

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

(Mira mi violín aquí: violín )


Supongo que esto podría funcionar, pero la respuesta correcta se ejecuta más rápido y más corto, siempre es mejor evitar RegEx tanto como sea posible, ya que se sabe que es más lento que otros métodos
evilReiko

2

Hola Prueba este código a continuación

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

¿Cómo harías esto si en lugar de x tuviéramos otra cadena? Buena solución!
Mona Jalal

2

Use replaceAll en lugar de reemplazar

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

Esto debería darte la respuesta deseada.


reemplazar termina usando replaceAll. Mira en la implementación. Así es como se implementa String # replace: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";da "deletesalllankstoo"
Kaplan

0

Aquí hay una función lambda que elimina todos los caracteres pasados ​​como cadena

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"

Esta solución tiene en cuenta que la Cadena resultante, a diferencia de replace(), nunca se vuelve más grande que la Cadena inicial al eliminar caracteres. Por lo tanto, evita la asignación y la copia repetidas al tiempo que se agrega carácter a lo StringBuilderque se replace()hace.
Sin mencionar la generación inútil Patterny las Matcherinstancias en replace()que nunca son necesarias para la eliminación.
A diferencia de replace()esta solución, puede eliminar varios caracteres de una sola vez.


La programación funcional / lambdas es muy moderna en este momento, pero usarla para crear una solución que sea 10 veces más larga que la respuesta elegida no puede justificarse en mi humilde opinión, de ahí el voto negativo.
Volksman

str.replace("…", "")crea instancias private Pattern(…)y luego en las llamadas de patrón generadas public String replaceAll(String repl). Entonces sucedieron las siguientes llamadas a funciones: return Pattern.compile(target.toString(), Pattern.LITERAL).matcher( this).replaceAll(Matcher.quoteReplacement(replacement.toString())); - vea el comentario de Sal_Vader_808. En general, ca 3 veces más que mi solución lambda de cadera . Y aquí se explica muy bien por qué mi solución lambda de cadera también es más rápida: ¿Por qué es tan lento el String :: replace () de Java?
Kaplan

en lo propio : si realmente se tratara del tamaño de la solución, algunas otras soluciones dos veces más grandes o las soluciones que requieren una biblioteca externa serían candidatos más adecuados para la crítica. Una extensión de lenguaje que ha sido parte del lenguaje durante años desde que Java 8 no es realmente moderno . Un problema general con el sistema de puntuación es que el factor tiempo pesa más que la calidad de una solución. Como resultado, las soluciones más actualizadas y, a veces, incluso mejores se encuentran cada vez más en el tercio posterior.
Kaplan

Me refería a 10 veces más en términos de código, no de velocidad de ejecución. Cualquier cosa que compila un patrón regex cada vez que se llama puede ser mucho más lento. Realmente necesitaría almacenar en caché el comparador compilado y reutilizarlo si usa dicha expresión regular a alta frecuencia (OP no dice en qué escenario se usa, podría ser un escenario raro para limpiar los datos de un envío de formulario o podría usarse en un apretado bucle se llama 1000 de veces por segundo).
Volksman

Con respecto a las preocupaciones de rendimiento, agregué una nueva respuesta que ejecuta un punto de referencia rápido en una variedad de respuestas proporcionadas. Si el OP realiza esta operación con frecuencia, entonces deben evitar la opción String.replace () ya que la recompilación repetida del patrón regex debajo del capó es muy costosa.
Volksman

0

Evaluación de las respuestas principales con un punto de referencia de rendimiento que confirma las preocupaciones de que la respuesta actual elegida haga costosas operaciones de expresiones regulares bajo el capó

Hasta la fecha, las respuestas proporcionadas vienen en 3 estilos principales (ignorando la respuesta de JavaScript;)):

  • Use String.replace (charsToDelete, ""); que usa expresiones regulares debajo del capó
  • Utilizar lambda
  • Use una implementación simple de Java

En términos de tamaño de código, claramente el String.replace es el más conciso. La implementación simple de Java es un poco más pequeña y limpia (en mi humilde opinión) que la Lambda (no me malinterpreten, uso Lambdas a menudo cuando son apropiadas)

La velocidad de ejecución fue, en orden de más rápida a más lenta: implementación simple de Java, Lambda y luego String.replace () (que invoca expresiones regulares).

Con mucho, la implementación más rápida fue la implementación simple de Java ajustada para que preasigne el búfer StringBuilder a la longitud máxima posible del resultado y luego simplemente agregue caracteres al búfer que no están en la cadena "caracteres para eliminar". Esto evita las reasignaciones que se producirían para cadenas> 16 caracteres de longitud (la asignación predeterminada para StringBuilder) y evita el impacto de rendimiento "deslizar a la izquierda" de eliminar caracteres de una copia de la cadena que se produce es la implementación de Lambda.

El siguiente código ejecuta una prueba de referencia simple, ejecuta cada implementación 1,000,000 de veces y registra el tiempo transcurrido.

Los resultados exactos varían con cada ejecución, pero el orden de rendimiento nunca cambia:

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

La implementación de Lambda (como se copió de la respuesta de Kaplan) puede ser más lenta porque realiza un "desplazamiento a la izquierda por uno" de todos los caracteres a la derecha del carácter que se está eliminando. Obviamente, esto empeoraría para cadenas más largas con muchos caracteres que requieren eliminación. También puede haber algo de sobrecarga en la implementación de Lambda en sí.

La implementación String.replace, utiliza expresiones regulares y realiza una "compilación" de expresiones regulares en cada llamada. Una optimización de esto sería usar regex directamente y almacenar en caché el patrón compilado para evitar el costo de compilarlo 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));
    }
}

Si se llama a la función lambda como se pretende, el tiempo es el siguiente (nadie envuelve una función lambda en una función miembro) . Además, su deleteCharsReplace () está mal implementado: reemplaza una Cadena "XYZ" y no como se requiere 'X', 'Y' y 'Z' lo fromString.replace("X", "").replace("Y", "").replace("Z", "");que necesitaría. Ahora obtenemos el momento correcto: Inicio simple Hora: 759 | Inicio lambda Hora: 1092 | Iniciar eliminarCharsLambda () Hora: 1420 | Inicio reemplazar tiempo corregido: 4636
Kaplan

"nadie envuelve una función lambda en una función miembro", excepto con el propósito de llamarla en un escenario de referencia para que sea coherente con la forma en que se llaman las otras implementaciones.
Volksman

Me acabo de dar cuenta de que el OP preguntó sobre la eliminación de todas las apariciones de un solo carácter, pero su respuesta cambió el alcance para tratar con un conjunto de caracteres. La implementación de respuesta "aceptada" que utilicé no lo hace y nunca tuvo la intención de atender a múltiples caracteres. Así que he actualizado el punto de referencia anterior para reflejar esto y los tiempos de referencia. Por cierto, si desea aumentar el alcance para admitir la llamada de múltiples caracteres, reemplazar varias veces es costoso. Es mejor cambiar a una sola llamada para reemplazar All ("[XYZ]", "")
Volksman

La función que se muestra en la solución solo se inicia una vez cuando se llama. Ajustar la definición de función adicionalmente a la llamada de función en la función miembro tiene el único efecto de distorsionar el punto de referencia.
Kaplan

Es prácticamente imposible comparar adecuadamente los métodos de duración rápida haciendo una sola llamada, ya que la variación de cada llamada es muy alta. Por lo tanto la evaluación comparativa normalmente implica muchas llamadas repetidas al mismo método y luego se evalúa el tiempo total de comparar con los tiempos totales de las alternativas (o calcular un promedio, si es necesario) ..
Volksman

0

Deberá poner los caracteres que deben eliminarse dentro de los corchetes durante el tiempo de reemplazo. El código de ejemplo será el siguiente:

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

-3

Puede usar str = str.replace("X", "");como se mencionó anteriormente y estará bien. Para su información ''no es un carácter vacío (o válido) pero '\0'es.

Entonces podrías usar str = str.replace('X', '\0');en su lugar.


99
Esto es incorrecto. '\ 0' producirá un carácter nulo real. str.replace ('X', '\ 0') es equivalente a str.replace ("X", "\ u0000") que no es lo que el OP quería
Andrey
Al usar nuestro sitio, usted reconoce que ha leído y comprende nuestra Política de Cookies y Política de Privacidad.
Licensed under cc by-sa 3.0 with attribution required.