C ++ 문자열에서 문자의 모든 발생을 제거하는 방법


98

다음을 사용하고 있습니다.

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

그러나 이것은 컴파일 오류를 제공합니다.


8
''실제로 캐릭터가 아닙니다.
n. '대명사'm.

4
글쎄, 당신이 얻는 오류를 아는 것이 확실히 도움이 될 것입니다.
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");

이 모든 것은 참조 웹 사이트 에 잘 문서화되어 있습니다. 그러나 이러한 기능을 몰랐다면 이런 종류의 일을 손으로 쉽게 할 수 있습니다.

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 컨테이너 재 할당 전략 때문 이라고 생각합니다 .
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 (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;
}

이것이 내가 한 방법입니다.

또는 Antoine이 언급 한대로 할 수 있습니다.

동일한 문제에 대한 답 이있는이 질문 을 참조하십시오 . 귀하의 경우 :

#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

다른 답변을 기반으로 주어진 문자열에서 모든 특수 문자를 제거한 예제가 하나 더 있습니다.

#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 방법이 작동한다고 생각하지만 include와의 호환성 문제를 제공했기 때문에이 작은 함수를 작성했습니다.

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

주어진 char 목록의 모든 발생을 제거합니다.

루프가 첫 번째 일치 이후에 반환되기 때문에 이것은 또한 약간 더 효율적일 수 있으므로 실제로 비교를 덜 수행합니다.


1
맞아요. 직접 작성하는 것보다 표준 C ++ 헤더를 사용할 수없는 이유를 더 잘 찾으십시오.
xtofl

글쎄, 그것은 개인적인 의견입니다 xtofl, 당신이 특별히 필요한 것을 작성하는 것보다 실제로 그것이 무엇을하는지 또는 성능을 알지 못하는 세 번째 코드를 사용하는 것이 항상 좋은 것은 아닙니다.
Damien

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

기본적으로 주어진 문자를 찾을 때마다 오프셋을 진행하고 문자를 올바른 색인으로 재배치합니다. 이것이 정확하거나 효율적인지 모르겠습니다. 저는 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());

str에서 대문자 Y와 S를 제거하고 "ourtring"을 남깁니다.

참고 remove알고리즘과 헤더 필요 <algorithm>포함합니다.


그래, 나는 그가 탈락 했나 배열 문자를 통해 묵시적 루프 있다고 생각
RichardPlunkett
당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.