Удалить все вхождения char из строки


311

Я могу использовать это:

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

Есть ли способ удалить все вхождения символа Xиз строки в Java?

Я попробовал это и не то, что я хочу str.replace('X',' '); //replace with space


3
Вы пытались заменить односимвольные строки?
peter.murray.rust

Ответы:


523

Попробуйте использовать перегрузку, которая принимает CharSequenceаргументы (например, String), а не char:

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

2
Первым аргументом является регулярное выражение, иногда оно не будет работать должным образом, особенно если эта строка поступает из пользовательского ввода.
вбеженар

9
@vsb: не правда. Оба аргумента этой конкретной перегрузки CharSequence. docs.oracle.com/javase/7/docs/api/java/lang/…
LukeH

Что делать, если Xтип имеет тип char?
KNU

7
@ Кунал: Полагаю, toStringсначала тебе это понадобится . Так что ваш код будет выглядеть примерно такstr = str.replace(yourChar.toString(), "");
LukeH

Обратите внимание, что вы можете использовать Unicode Escape, например, не удалить noncharactersstr = str.replace("\uffff", "");
Хайме Hablutzel

42

С помощью

public String replaceAll(String regex, String replacement)

буду работать.

Использование будет str.replace("X", "");.

проведение

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

возвращает:

lakjsdf xx

6
Regex, вероятно, излишне для этого, если вы не ограничены поддержкой Java 1.4 - начиная с версии 1.5 существует replaceперегрузка, которая требует простого CharSequence.
LukeH

3
@LukeH, это декомпилированный источник в String.replace. Он использует регулярные выражения. Я согласен, что это регулярное выражение кажется тяжелым, но это то, что находится под капотом даже для принятого ответа выше. public String replace (CharSequence var1, CharSequence var2) {return Pattern.compile (var1.toString (), 16) .matcher (this) .replaceAll (Matcher.quoteReplacement (var2.toString ())); }
Перри Тью,


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

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

Это пример того, где я удалил персонажа из строки.


4
Это очень неэффективно, особенно по сравнению с принятым ответом.
Эрик Робертсон

3
Я думаю, что этот ответ работает, но правильный ответ он короче и быстрее
evilReiko

2

Мне нравится использовать RegEx по этому поводу:

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

где g означает глобальный, поэтому он пройдет всю строку и заменит все X на ''; если вы хотите заменить оба X и x, вы просто говорите:

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

(см. мою скрипку здесь: скрипка )


Я думаю, это может сработать, но правильный ответ выполняется быстрее и короче, всегда лучше избегать RegEx, насколько это возможно, так как известно, что он медленнее других методов
evilReiko

2

Здравствуйте, попробуйте этот код ниже

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

как бы вы сделали это, если бы вместо х у нас была другая строка? Отличное решение!
Мона Джалал

2

Используйте replaceAll вместо replace

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

Это должно дать вам желаемый ответ.


замена заканчивается с использованием replaceAll. Посмотрите на реализацию. Вот как реализована замена String #: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";дает "deletesalllankstoo"
Каплан

0

вот лямбда-функция, которая удаляет все символы, переданные в виде строки

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"

Это решение учитывает, что результирующая строка - в отличие от replace()- никогда не становится больше, чем начальная строка при удалении символов. Таким образом, он избегает повторного выделения и копирования при добавлении символьно в StringBuilderas replace().
Не говоря уже о бессмысленном поколении Patternи Matcherэкземплярах replace(), которые никогда не нужны для удаления.
В отличии от replace()этого решения можно удалить несколько символов одним махом.


Лямбда / Функциональное программирование сейчас очень модно, но использование его для создания решения, которое в 10 раз длиннее выбранного ответа, не может быть оправдано ИМХО, отсюда и отрицательный голос.
Volksman

str.replace("…", "")создает экземпляры, private Pattern(…)а затем генерирует вызовы шаблонов public String replaceAll(String repl). Таким образом, произошли следующие вызовы функций: return Pattern.compile(target.toString(), Pattern.LITERAL).matcher( this).replaceAll(Matcher.quoteReplacement(replacement.toString())); - см. Комментарий Sal_Vader_808. В целом примерно в 3 раза дольше , чем мой хип лямбда - решения. И здесь хорошо объясняется, почему мое решение для лямбда- тазобедренного сустава также быстрее: почему Java String :: replace () такая медленная?
Каплан

в своем роде : если бы речь шла о размере решения, некоторые другие решения, вдвое большие, или решения, требующие внешней библиотеки, были бы более подходящими кандидатами для критики. Расширение языка, которое было частью языка в течение многих лет после Java 8, на самом деле не является модным . Общая проблема с системой подсчета очков состоит в том, что фактор времени весит больше, чем качество решения. В результате в последней трети все чаще находят более современные, а иногда и лучшие решения.
Каплан

Я имел в виду в 10 раз больше с точки зрения кода, а не скорости выполнения. Все, что компилирует шаблон регулярного выражения при каждом вызове, может быть намного медленнее. Вам действительно нужно было бы кэшировать скомпилированное сопоставление и использовать его повторно, если вы используете такое регулярное выражение на высокой частоте (OP не говорит, какой сценарий он использует - это может быть редкий сценарий для очистки данных из представления формы или может использоваться в тесном цикл вызывается тысячи раз в секунду).
Volksman

Что касается проблем с производительностью, я добавил новый ответ, который позволяет быстро оценить различные ответы. Если OP выполняет эту операцию часто, им следует избегать опции String.replace (), так как повторная перекомпиляция шаблона регулярных выражений под капотом очень дорогая.
Volksman

0

Оценка основных ответов с помощью теста производительности, который подтверждает опасения, что текущий выбранный ответ делает дорогостоящие операции регулярного выражения под капотом

На сегодняшний день предоставленные ответы представлены в 3 основных стилях (без учета ответа JavaScript;)):

  • Использовать String.replace (charsToDelete, ""); который использует регулярные выражения под капотом
  • Используйте лямбду
  • Используйте простую реализацию Java

С точки зрения размера кода, String.replace является наиболее кратким. Простая реализация Java немного меньше и чище (IMHO), чем лямбда (не поймите меня неправильно - я часто использую лямбды там, где они уместны)

Скорость выполнения была в порядке от самой быстрой до самой медленной: простая реализация Java, Lambda, а затем String.replace () (которая вызывает регулярное выражение).

Безусловно, самой быстрой реализацией была простая реализация Java, настроенная таким образом, чтобы она предварительно выделяла буфер StringBuilder для максимально возможной длины результата, а затем просто добавляла символы в буфер, которых нет в строке «символы для удаления». Это позволяет избежать любых перераспределений, которые могут произойти для строк длиной более 16 символов (распределение по умолчанию для StringBuilder), и позволяет избежать «снижения влево» при удалении символов из копии строки, которая возникает, является реализацией Lambda.

Приведенный ниже код запускает простой тест производительности, запускает каждую реализацию 1 000 000 раз и регистрирует истекшее время.

Точные результаты меняются с каждым прогоном, но порядок производительности никогда не меняется:

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

Реализация лямбды (как скопировано из ответа Каплана) может быть медленнее, потому что она выполняет «сдвиг влево на один» из всех символов справа от удаляемого символа. Это очевидно ухудшится для более длинных строк с большим количеством символов, требующих удаления. Также могут быть некоторые издержки в самой реализации Lambda.

Реализация String.replace использует регулярное выражение и выполняет регулярное выражение «компилировать» при каждом вызове. Оптимизация этого заключается в прямом использовании регулярных выражений и кэшировании скомпилированного шаблона, чтобы избежать затрат на его компиляцию каждый раз.

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

Если лямбда-функция вызывается так, как она предназначена, время будет следующим (никто не превращает лямбда-функцию в функцию-член) . Кроме того, ваш deleteCharsReplace () реализован неправильно: он заменяет одну строку «XYZ», а не так, как требуется «X», «Y» и «Z», что fromString.replace("X", "").replace("Y", "").replace("Z", "");потребуется. Теперь мы получаем правильное время: Начните с простого Время: 759 | Старт лямбды Время: 1092 | Запустить deleteCharsLambda () Время: 1420 | Начало замены исправлено Время: 4636
Каплан

«никто не превращает лямбда-функцию в функцию-член» - за исключением того, что она вызывается в тестовом сценарии, чтобы она соответствовала способу вызова других реализаций.
Volksman

Я только что понял, что ОП спросил об удалении всех вхождений одного символа, но ваш ответ изменил область действия, чтобы иметь дело с набором символов. Реализация «принятого» ответа, которую я использовал, не имеет и никогда не предназначалась для обслуживания нескольких символов. Поэтому я обновил приведенный выше тест, чтобы отразить это и время тестирования. Кстати, если вы хотите увеличить область для поддержки нескольких символов, вызов замены несколько раз обходится дорого. Лучше переключиться на один вызов для замены всех ("[XYZ]", "")
Volksman

Функция, показанная в решении, вызывается только один раз при вызове. В дополнение к определению функции в дополнение к вызову функции функция-член имеет единственный эффект искажения эталона.
Каплан

Практически невозможно правильно оценить методы быстрой продолжительности, сделав один вызов, так как дисперсия каждого вызова очень высока. Таким образом, для сравнительного анализа обычно используется многократные вызовы одного и того же метода, а затем оценивается общее время для сравнения с общим временем альтернатив (или для вычисления среднего значения, если требуется) ..
Volksman

0

Вам нужно будет поставить символы должны быть удалены в квадратных скобках во время замены. Пример кода будет следующим:

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

-3

Вы можете использовать, str = str.replace("X", "");как упоминалось ранее, и все будет в порядке. Для вашей информации ''не пустой (или действительный) символ, но '\0'есть.

Таким образом, вы могли бы использовать str = str.replace('X', '\0');вместо этого.


9
это неверно '\ 0' приведет к фактическому нулевому символу. str.replace ('X', '\ 0') эквивалентен str.replace ("X", "\ u0000"), что совсем не то, чего хотел ОП
Андрей
Используя наш сайт, вы подтверждаете, что прочитали и поняли нашу Политику в отношении файлов cookie и Политику конфиденциальности.
Licensed under cc by-sa 3.0 with attribution required.