C ++ dizesinde bir karakterin tüm oluşumlarını kaldırma


105

Ben şunu kullanıyorum:

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

Ancak bu derleme hatası veriyor.


9
''aslında bir karakter değil.
n. zamirler 'm.

5
Eh, aldığınız hatayı bilmeniz kesinlikle yardımcı olacaktır.
SBI

3
iyi olun, değiştirmenin uygun bir düşünce olduğu pek çok bağlam var, sadece bunun değil.
RichardPlunkett

Yanıtlar:


176

Temel olarak, replacebir karakteri başka bir karakterle değiştirir ve ''bir karakter değildir. Aradığınız şey erase.

Aynı soruna cevap veren bu soruya bakın . Senin durumunda:

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

Veya boostbu sizin için bir seçenekse kullanın , örneğin:

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

Bütün bunlar referans web sitelerinde iyi bir şekilde belgelenmiştir . Ancak bu işlevleri bilmiyorsanız, bu tür şeyleri elle kolayca yapabilirsiniz:

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
Sağladığınız algoritma değil O(n^2)mi?
jww

1
@jww: Sanırım son kod örneğinden bahsediyorsunuz ve norijinal dize uzunluğu. Her giriş karakteri için 1 karakter testi yapıyorum O(1)ve 0 veya 1 karakter ekliyorum. Karakter eklemek O(1)yeterli bellek ayrılmışsa veya O(current_length)yeni bir tampon ayrılmışsa. Döngüden output.reserve(str.size())önce yaparsanız , bu asla olmaz ve küresel bir O(n)maliyetiniz olur. Aksi takdirde asimptotik olarak, maliyetin O(n . log(n) )STL konteyner yeniden tahsis stratejisinden kaynaklandığını tahmin ediyorum .
Antoine

5
#İnclude <algorithm>
S Meaden

Güzel cevap. Cevabın birçok çözüm içermesi her zaman iyidir. Benim için çözüm foren uygun olanıdır.
Dmitry Nichiporenko

@DmitryNichiporenko for ile cevap en uygun olamaz. Bir yükleminiz varsa veya boş olmayan bir çıktınız varsa şunu dikkate almayı tercih ederim: output.reserve (str.size () + output.size ()); std :: copy_if (str.begin (), str.end (), std :: back_inserter (çıktı), [] (char c) {dönüş koşulu (c);});
jimifiki

11

Algoritma , belirli bir sıradaki öğe başınastd::replace çalışır (bu nedenle, öğeleri farklı öğelerle değiştirir ve hiçbir şeyle değiştiremez ). Ama boş karakter yok . Bir diziden öğeleri kaldırmak istiyorsanız, aşağıdaki öğelerin taşınması gerekir ve bu şekilde çalışmaz.std::replace

Bunu başarmak için std::remove( ile birliktestd::erase ) kullanmayı deneyebilirsiniz .

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

9

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

Ben böyle yaptım.

Veya Antoine'ın bahsettiği gibi yapabilirsiniz:

Aynı soruna cevap veren bu soruya bakın . Senin durumunda:

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

1

Filtrelenmiş dizeyle doldurmak için bir predicateve / veya boş olmayan seçeneğiniz varsa, şunları outputdikkate alırım:

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

Orijinal soruda yüklem [](char c){return c != 'a';}


1

Bu kod, karakterlerin tekrarını kaldırır, yani giriş aaabbcc ise çıktı abc olacaktır. (bu kodun çalışması için dizinin sıralanması gerekir)

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

Diğer yanıtlara dayanarak, belirli bir dizedeki tüm özel karakterleri kaldırdığım bir örnek daha var:

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

Giriş ve Çıkış:

Input:ra,..pha
Output:rapha

Input:ovo,
Output:ovo

Input:a.vo
Output:avo

Input:oi?
Output:oi

0

En iyi cevaptan% 70 Daha Hızlı Çözüm

        void removeCharsFromString(std::string& str, const char* charsToRemove)
        {
            size_t charsToRemoveLen = strlen(charsToRemove);
            std::remove_if(str.begin(), str.end(), [charsToRemove, charsToRemoveLen](char ch) -> bool
                {
                    for (int i = 0; i < charsToRemoveLen; ++i) {
                        if (ch == charsToRemove[i])
                            return true;
                    }
                    return false;
                });
        }

-1

Sanırım std: remove yöntemi çalışıyor, ancak kapsayıcılarla bazı uyumluluk sorunları veriyordu, bu yüzden bu küçük işlevi yazdım:

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

Sadece kullan

myString = removeCharsFromString (myString, "abc \ r");

ve verilen karakter listesinin tüm oluşumunu kaldıracaktır.

Döngü ilk eşleşmeden sonra döndüğü için bu biraz daha verimli olabilir, bu yüzden aslında daha az karşılaştırma yapıyoruz.


1
Doğru tahmin et. Kendi başlığınızı yazmak yerine, neden standart C ++ başlıklarını kullanamadığınızı daha iyi öğrenin.
xtofl

Bu kişisel bir görüş xtofl, 3. kodu kullanmak her zaman iyi değildir, özellikle ihtiyacınız olan şeyi yazmak yerine ne yaptığını veya performanslarını bilmiyorsunuz.
Damien

1
Ne demek istediğini anlıyorum. Benimki yerine profesyonel tam zamanlı kütüphane yazarları tarafından gözden geçirilmiş, test edilmiş, optimize edilmiş versiyonu seçmeme neden olan tevazu. Standart fonksiyonları yanı sıra çalışma zamanı karmaşıklığı: kütüphane gerekli bilgi olarak kabul edilebilir.
xtofl

Dizeler bir yana, C ++ problemine C çözümü. Bunun reddedilmesi gerektiğini düşünmüyorum.
Baykuş

-1

Ben böyle yaparım:

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

Temel olarak, ne zaman belirli bir karakter bulsam, ofseti ilerletirim ve karakteri doğru dizine yerleştiririm. Bunun doğru mu yoksa verimli mi olduğunu bilmiyorum, (yine) C ++ 'dan başlıyorum ve bu konudaki herhangi bir girdiyi takdir ediyorum.


4
4 ay sonra bu soruya dönüp baktığımda, neden std :: erase veya std :: replace kullanmadığımı gerçekten bilmiyorum.
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());

Büyük Y ve S'yi str'den kaldırarak "bizimtring'imizi" bırakır.

Bunun removebir algoritma olduğunu ve başlığın <algorithm>dahil edilmesi gerektiğini unutmayın .


evet, sanırım hte dizi karakterlerinde örtük bir döngü var
RichardPlunkett
Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.