Cách xóa tất cả các lần xuất hiện của một ký tự trong chuỗi c ++


98

Tôi đang sử dụng sau:

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

Nhưng điều này gây ra lỗi biên dịch.


8
''thực sự không phải là một nhân vật.
n. 'đại từ' m.

3
Chà, chắc chắn sẽ hữu ích khi biết lỗi bạn đang gặp phải.
SBI

3
tốt đẹp, có rất nhiều bối cảnh mà thay thế là một suy nghĩ thích hợp, chỉ không phải cái này.
RichardPlunkett

Câu trả lời:


171

Về cơ bản, replacethay thế một ký tự bằng một ký tự khác và ''không phải là một ký tự. Những gì bạn đang tìm kiếm là erase.

Xem câu hỏi này trả lời cùng một vấn đề. Trong trường hợp của bạn:

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

Hoặc sử dụng boostnếu đó là một tùy chọn cho bạn, như:

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

Tất cả những điều này đều được ghi chép đầy đủ trên các trang web tham khảo . Nhưng nếu bạn không biết những chức năng này, bạn có thể dễ dàng làm những việc này bằng tay:

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
Không phải là thuật toán bạn đã cung cấp O(n^2)?
jww

@jww: Tôi giả sử bạn đang nói về mẫu mã cuối cùng và nlà độ dài chuỗi ban đầu. Đối với mỗi ký tự đầu vào, tôi thực hiện kiểm tra 1 ký tự O(1)và thêm 0 hoặc 1 ký tự. Ký tự nối thêm là O(1)đủ bộ nhớ được dự trữ hoặc O(current_length)nếu một bộ đệm mới được cấp phát. Nếu bạn làm output.reserve(str.size())trước vòng lặp, điều này không bao giờ xảy ra và bạn phải O(n)trả chi phí toàn cầu . Nếu không, tôi đoán chi phí là O(n . log(n) )do chiến lược phân bổ lại vùng chứa STL.
Antoine

5
Tôi cần #include <algorithm>
S Meaden

Câu trả lời rất hay. Sẽ luôn tốt nếu câu trả lời có nhiều giải pháp. Đối với tôi, giải pháp với forlà phù hợp nhất.
Dmitry Nichiporenko

@DmitryNichiporenko câu trả lời với for không thể phù hợp nhất. Nếu bạn có một vị từ hoặc một đầu ra không trống, tôi muốn xem xét: output.reserve (str.size () + output.size ()); std :: copy_if (str.begin (), str.end (), std :: back_inserter (output), [] (char c) {return predicate (c);});
jimifiki

10

Thuật toán std::replacehoạt động trên mỗi phần tử trên một chuỗi nhất định (vì vậy nó thay thế các phần tử bằng các phần tử khác nhau và không thể thay thế nó bằng không ). Nhưng không có ký tự trống . Nếu bạn muốn xóa các phần tử khỏi một chuỗi, các phần tử sau phải được di chuyểnstd::replacekhông hoạt động như vậy.

Bạn có thể cố gắng sử dụng std::remove( cùng vớistd::erase ) để đạt được điều này.

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

8

Sử dụng 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;
}

Đây là cách tôi đã làm điều đó.

Hoặc bạn có thể làm như Antoine đã đề cập:

Xem câu hỏi này trả lời cùng một vấn đề. Trong trường hợp của bạn:

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

1

Mã này loại bỏ sự lặp lại của các charecters, tức là nếu đầu vào là aaabbcc thì đầu ra sẽ là 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

Trong trường hợp bạn có predicatevà / hoặc không để trống outputđể điền vào chuỗi đã lọc, tôi sẽ xem xét:

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

Trong câu hỏi ban đầu, vị ngữ là [](char c){return c != 'a';}


0

Dựa trên các câu trả lời khác, đây là một ví dụ khác mà tôi đã xóa tất cả các ký tự đặc biệt trong một chuỗi nhất định:

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

Đầu vào so với Đầu ra:

Input:ra,..pha
Output:rapha

Input:ovo,
Output:ovo

Input:a.vo
Output:avo

Input:oi?
Output:oi

-1

Tôi đoán phương pháp std: remove hoạt động nhưng nó gây ra một số vấn đề tương thích với bao gồm vì vậy tôi đã kết thúc bằng cách viết hàm nhỏ này:

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

Chỉ cần sử dụng như

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

và nó sẽ loại bỏ tất cả sự xuất hiện của danh sách char đã cho.

Điều này cũng có thể hiệu quả hơn một chút vì vòng lặp trở lại sau trận đấu đầu tiên, vì vậy chúng tôi thực sự thực hiện ít so sánh hơn.


1
Bạn đoán đúng. Thay vì viết của riêng bạn, hãy tìm hiểu lý do tại sao bạn không thể sử dụng tiêu đề C ++ chuẩn.
xtofl

Đó là ý kiến ​​cá nhân của xtofl, Không phải lúc nào bạn cũng sử dụng tốt mã thứ 3 mà bạn thực sự không biết nó có tác dụng gì cũng như hiệu suất hơn là viết những gì bạn cần cụ thể.
Damien

1
Tôi hiểu ý bạn. Mặc dù vậy, chính sự khiêm tốn đã khiến tôi chọn phiên bản đã được xem xét, thử nghiệm, tối ưu hóa bởi những người viết thư viện toàn thời gian chuyên nghiệp, hơn là của riêng tôi. Các tiêu chuẩn thư viện có thể được coi là kiến thức cần thiết: chức năng của mình cũng như sự phức tạp của nó khi chạy.
xtofl

Sang một bên, đó là một giải pháp C cho một vấn đề C ++. Tôi không nghĩ rằng điều này nên được bỏ phiếu xuống.
Owl

-1

Đây là cách tôi làm điều đó:

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

Về cơ bản, bất cứ khi nào tôi tìm thấy một char nhất định, tôi sẽ tăng phần bù và chuyển vị trí của char đến đúng chỉ mục. Tôi không biết liệu điều này có chính xác hay hiệu quả hay không, tôi đang bắt đầu (một lần nữa) ở C ++ và tôi đánh giá cao bất kỳ đầu vào nào về điều đó.


4
Nhìn lại câu hỏi này 4 tháng sau, tôi thực sự không biết tại sao tôi không sử dụng std :: delete hoặc 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());

Sẽ xóa Y và S viết hoa khỏi str, để lại "ourtring".

Lưu ý rằng đó removelà một thuật toán và cần có tiêu đề <algorithm>.


yeah, tôi nghĩ rằng đó là một vòng lặp ngụ ý qua HTE chars mảng ông rời ra
RichardPlunkett
Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.