C ++文字列で文字の出現をすべて削除する方法


98

私は以下を使用しています:

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

しかし、これはコンパイルエラーを引き起こしています。


8
''確かにキャラクターではありません。
n。「代名詞」m。

3
まあ、それは確かにあなたが得ているエラーを知るのに役立ちます。
SBI

3
いいですね、置換が適切な考えであるコンテキストはたくさんありますが、これだけではありません。
RichardPlunkett、2013

回答:


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

これらのすべては、参照 Webサイトに十分に文書化されています。しかし、これらの機能を知らなかった場合は、このようなことを手で簡単に行うことができます。

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、元の文字列の長さだと思います。入力文字ごとに、1文字のテストO(1)と0または1文字の追加を行います。文字追加はO(1)、十分なメモリが予約されているか、またはO(current_length)新しいバッファが割り当てられている場合です。output.reserve(str.size())ループの前に行うと、これは発生せず、グローバルなO(n)コストがかかります。それ以外の場合は漸近的に、コストはO(n . log(n) )STLコンテナーの再割り当て戦略が原因であると思います。
アントワーヌ

5
#include <algorithm>が必要
S Meaden 2017

素敵な答え。答えに多くの解決策が含まれている場合、それは常に良いことです。私にとっては、のソリューションがfor最も適しています。
Dmitry Nichiporenko

@DmitryNichiporenko forの答えは最適ではありません。述語または空でない出力がある場合は、次のように検討します。output.reserve(str.size()+ output.size()); std :: copy_if(str.begin()、str.end()、std :: back_inserter(output)、[](char c){return predicate(c);});
jimifiki

10

アルゴリズムは、指定されたシーケンスの要素ごとにstd::replace機能します(そのため、要素を別の要素で置き換え、何も置き換えられません)。しかし、空の文字はありません。シーケンスから要素を削除したい場合、次の要素を移動する必要があり、このように動作しません。std::replace

これを実現するためにstd::remove(と一緒にstd::erase)を使用してみることができます。

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

8

使用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

このコードは、文字の繰り返しを削除します。つまり、入力が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;

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


0

他の回答に基づいて、ここに私が与えられた文字列のすべての特殊文字を削除したもう1つの例があります:

#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 2016

まあ、それは個人的な意見のxtoflです。具体的に必要なものを書くのではなく、実際に何をするか、パフォーマンスを知らない3番目のコードを使用することが常に良いとは限りません。
ダミアン

1
何と言いたいのか分かった。それは私が謙虚であることですが、私自身のバージョンではなく、プロのフルタイムライブラリライターによってレビュー、テスト、最適化されたバージョンを選択します。標準の機能だけでなく、実行時の複雑さ:ライブラリが必要な知識とみなすことができます。
xtofl

文字列はさておき、C ++の問題に対するCの解決策です。これは否決されるべきではないと思います。
フクロウ

-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を使用しなかったのか、本当にわかりません。
Ricardo Pieper

-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>含める必要があることに注意してください。


そうです、彼が除外した配列文字の暗黙のループがあると思います
RichardPlunkett
弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.