วิธีลบเหตุการณ์ทั้งหมดของอักขระในสตริง c ++


109

ฉันใช้สิ่งต่อไปนี้:

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

แต่นี่เป็นข้อผิดพลาดในการคอมไพล์


10
''ไม่ใช่ตัวละครแน่นอน
. 'สรรพนาม' ม.

6
แน่นอนว่าจะช่วยให้ทราบข้อผิดพลาดที่คุณได้รับ
SBI

3
จะดีมีบริบทมากมายที่การแทนที่เป็นความคิดที่เหมาะสมไม่ใช่สิ่งนี้
RichardPlunkett

คำตอบ:


180

โดยทั่วไป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

1
@jww: ฉันคิดว่าคุณกำลังพูดถึงตัวอย่างโค้ดสุดท้ายและnเป็นความยาวสตริงดั้งเดิม สำหรับอักขระอินพุตแต่ละตัวฉันทำการทดสอบO(1)1 อักขระและต่อท้าย 0 หรือ 1 อักขระ อักขระผนวกเป็นO(1)หน่วยความจำที่สงวนไว้เพียงพอหรือO(current_length)หากมีการจัดสรรบัฟเฟอร์ใหม่ หากคุณทำoutput.reserve(str.size())ก่อนการวนซ้ำสิ่งนี้จะไม่เกิดขึ้นและคุณมีO(n)ต้นทุนทั่วโลก มิฉะนั้นโดยไม่มีอาการฉันเดาว่าต้นทุนเป็นO(n . log(n) )เพราะกลยุทธ์การจัดสรรคอนเทนเนอร์ใหม่ของ STL
Antoine

5
ฉันต้องการ #include <algorithm>
S Meaden

คำตอบที่ดี จะดีเสมอถ้าคำตอบมีวิธีแก้ปัญหามากมาย สำหรับฉันการแก้ปัญหาด้วยวิธีforนี้เหมาะสมที่สุด
Dmitry Nichiporenko

@DmitryNichiporenko คำตอบสำหรับไม่สามารถเหมาะสมที่สุด หากคุณมีเพรดิเคตหรือเอาต์พุตที่ไม่ว่างฉันอยากจะพิจารณา: output.reserve (str.size () + output.size ()); std :: copy_if (str.begin (), str.end (), std :: back_inserter (เอาต์พุต), [] (ถ่าน 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;
}

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

นี่คือวิธีที่ฉันทำ

หรือคุณสามารถทำตามที่ Antoine กล่าวถึง:

ดูคำถามนี้ ซึ่งตอบปัญหาเดียวกัน ในกรณีของคุณ:

#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

0

โซลูชันที่เร็วกว่าคำตอบด้านบน 70%

        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

ฉันเดาว่าวิธีการ std: ลบใช้งานได้ แต่มันมีปัญหาความเข้ากันได้บางอย่างกับการรวมดังนั้นฉันจึงเขียนฟังก์ชันเล็ก ๆ นี้:

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 ที่คุณไม่รู้ว่ามันทำอะไรหรือแสดงมากกว่าการเขียนสิ่งที่คุณต้องการโดยเฉพาะ
Damien

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

โดยทั่วไปเมื่อใดก็ตามที่ฉันพบถ่านที่กำหนดฉันจะเลื่อนค่าชดเชยและย้ายตำแหน่งถ่านไปยังดัชนีที่ถูกต้อง ฉันไม่รู้ว่าสิ่งนี้ถูกต้องหรือมีประสิทธิภาพฉันกำลังเริ่มต้น (อีกครั้ง) ที่ 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>รวมอยู่ด้วย


ใช่ฉันคิดว่ามีการวนซ้ำโดยนัยมากกว่าอักขระอาร์เรย์ hte ที่เขาทิ้งไว้
RichardPlunkett
โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.