Как удалить все вхождения символа в строку c ++


101

Я использую следующее:

replace (str1.begin(), str1.end(), 'a' , '')

Но это дает ошибку компиляции.


8
''действительно не персонаж.
п. 'местоимения' м.

4
Что ж, это, безусловно, поможет узнать, в какую ошибку вы получаете.
SBI

3
будьте внимательны, есть много контекстов, в которых замена является уместной мыслью, но не этим.
Ричард Планкетт, 02

Ответы:


171

По сути, replaceзаменяет символ другим и ''не является персонажем. То, что вы ищете erase.

См. Этот вопрос, который отвечает на ту же проблему. В твоем случае:

#include <algorithm>
str.erase(std::remove(str.begin(), str.end(), 'a'), str.end());

Или используйте, boostесли это вариант для вас, например:

#include <boost/algorithm/string.hpp>
boost::erase_all(str, "a");

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

std::string output;
output.reserve(str.size()); // optional, avoids buffer reallocations in the loop
for(size_t i = 0; i < str.size(); ++i)
  if(str[i] != 'a') output += str[i];

2
Разве вы не предоставили алгоритм O(n^2)?
jww

@jww: Я полагаю, вы говорите о последнем образце кода и nисходной длине строки. Для каждого входного символа я провожу тест на O(1)1 символ и добавляю 0 или 1 символ. Добавление символа O(1), O(current_length)если зарезервировано достаточно памяти или выделен новый буфер. Если вы сделаете это output.reserve(str.size())до цикла, этого никогда не произойдет, и у вас будут глобальные O(n)затраты. В противном случае, асимптотически, я предполагаю, что стоимость O(n . log(n) )связана со стратегией перераспределения контейнеров STL.
Антуан

5
Мне нужен #include <алгоритм>
S Meaden

Хороший ответ. Всегда хорошо, если в ответе много решений. Для меня forнаиболее подходит решение с .
Дмитрий Ничипоренко

@DmitryNichiporenko, ответ с for не может быть самым подходящим. Если у вас есть предикат или непустой вывод, я бы предпочел рассмотреть: output.reserve (str.size () + output.size ()); std :: copy_if (str.begin (), str.end (), std :: back_inserter (вывод), [] (char c) {предикат возврата (c);});
jimifiki

11

Алгоритм std::replaceработает для каждого элемента в заданной последовательности (поэтому он заменяет элементы другими элементами и не может заменить его ничем ). Но не бывает пустого персонажа. Если вы хотите удалить элементы из последовательности, следующие элементы должны быть перемещены , и std::replaceэто не работает.

Вы можете попробовать использовать std::remove( вместе сstd::erase ) для этого.

str.erase(std::remove(str.begin(), str.end(), 'a'), str.end());

9

Использование copy_if:

#include <string>
#include <iostream>
#include <algorithm>
int main() {
    std::string s1 = "a1a2b3c4a5";
    char s2[256];
    std::copy_if(s1.begin(), s1.end(), s2, [](char c){return c!='a';});
    std::cout << s2 << std::endl;
    return 0;
}

3
string RemoveChar(string str, char c) 
{
   string result;
   for (size_t i = 0; i < str.size(); i++) 
   {
          char currentChar = str[i];
          if (currentChar != c)
              result += currentChar;
   }
       return result;
}

Вот как я это сделал.

Или вы можете сделать, как сказал Антуан:

См. Этот вопрос, который отвечает на ту же проблему. В твоем случае:

#include <algorithm>
str.erase(std::remove(str.begin(), str.end(), 'a'), str.end());

1

Если у вас есть predicateи / или непустой элемент outputдля заполнения отфильтрованной строкой, я бы подумал:

output.reserve(str.size() + output.size());  
std::copy_if(str.cbegin(), 
             str.cend(), 
             std::back_inserter(output), 
             predicate});

В исходном вопросе предикат [](char c){return c != 'a';}


1

Этот код удаляет повторение символов, т. Е. Если ввод - aaabbcc, то вывод будет abc. (массив должен быть отсортирован, чтобы этот код работал)

cin >> s;
ans = "";
ans += s[0];
for(int i = 1;i < s.length();++i)
if(s[i] != s[i-1])
    ans += s[i];
cout << ans << endl;

0

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

#include <iostream>
#include <string>
#include <algorithm>

std::string chars(".,?!.:;_,!'\"-");

int main(int argc, char const *argv){

  std::string input("oi?");
  std::string output = eraseSpecialChars(input);   

 return 0;
}




std::string eraseSpecialChars(std::string str){

std::string newStr;
    newStr.assign(str);  

    for(int i = 0; i < str.length(); i++){
        for(int  j = 0; j < chars.length(); j++ ){
            if(str.at(i) == chars.at(j)){
                char c = str.at(i);
                newStr.erase(std::remove(newStr.begin(), newStr.end(), c), newStr.end());
            }
        }

    }      

return newStr; 
}

Вход против выхода:

Input:ra,..pha
Output:rapha

Input:ovo,
Output:ovo

Input:a.vo
Output:avo

Input:oi?
Output:oi

-1

Я предполагаю, что метод std: remove работает, но он вызывал некоторую проблему совместимости с включениями, поэтому я написал эту небольшую функцию:

string removeCharsFromString(const string str, char* charsToRemove )
{
    char c[str.length()+1]; // + terminating char
    const char *p = str.c_str();
    unsigned int z=0, size = str.length();
    unsigned int x;
    bool rem=false;

    for(x=0; x<size; x++)
    {
        rem = false;
        for (unsigned int i = 0; charsToRemove[i] != 0; i++)
        {
            if (charsToRemove[i] == p[x])
            {
                rem = true;
                break;
            }
        }
        if (rem == false) c[z++] = p[x];
    }

    c[z] = '\0';
    return string(c);
}

Просто используйте как

myString = removeCharsFromString (myString, «abc \ r»);

и он удалит все вхождения данного списка символов.

Это также может быть немного более эффективным, поскольку цикл возвращается после первого совпадения, поэтому на самом деле мы проводим меньше сравнений.


1
Вы угадали. Вместо того, чтобы писать свои собственные, лучше выяснить, почему нельзя использовать стандартные заголовки C ++.
xtofl

Что ж, это личное мнение, xtofl, не всегда хорошо использовать 3-й код, если вы на самом деле не знаете, что он делает, или производительности, вместо того, чтобы писать то, что вам конкретно нужно.
Дэмиен

1
Я понимаю, что ты имеешь в виду. Однако именно скромность заставляет меня выбирать версию, которая была проверена, протестирована и оптимизирована профессиональными разработчиками библиотеки, работающими полный рабочий день, а не моей собственной. Стандартной библиотеки можно считать необходимыми знаниями: его функции, а также его выполнения сложности.
xtofl

Помимо строк, это решение проблемы C ++ на языке C. Я не думаю, что это должно было быть отклонено.
Owl

-1

Вот как я это делаю:

std::string removeAll(std::string str, char c) {
    size_t offset = 0;
    size_t size = str.size();

    size_t i = 0;
    while (i < size - offset) {
        if (str[i + offset] == c) {
            offset++;
        }

        if (offset != 0) {
            str[i] = str[i + offset];
        }

        i++;
    }

    str.resize(size - offset);
    return str;
}

Обычно всякий раз, когда я нахожу данный char, я увеличиваю смещение и перемещаю char в правильный индекс. Я не знаю, правильно это или эффективно, я начинаю (снова) с C ++, и я был бы признателен за любой вклад по этому поводу.


4
Оглядываясь на этот вопрос через 4 месяца, я действительно не знаю, почему я не использовал std :: erase или std :: replace.
Рикардо Пипер,

-3
#include <string>
#include <algorithm>
std::string str = "YourString";
char chars[] = {'Y', 'S'};
str.erase (std::remove(str.begin(), str.end(), chars[i]), str.end());

Удалит заглавные буквы Y и S из str, оставив "ourtring".

Обратите внимание, что removeэто алгоритм, и он требует включения заголовка <algorithm>.


да, я думаю, что есть подразумеваемый цикл для символов массива, который он пропустил
Ричард Планкетт
Используя наш сайт, вы подтверждаете, что прочитали и поняли нашу Политику в отношении файлов cookie и Политику конфиденциальности.
Licensed under cc by-sa 3.0 with attribution required.