C ++의 문자열에서 특정 문자를 제거하는 방법은 무엇입니까?


96

예를 들어 사용자가 전화 번호를 입력했습니다.

cout << "Enter phone number: ";
INPUT: (555) 555-5555
cin >> phone;

문자열에서 "(", ")"및 "-"문자를 제거하고 싶습니다. 문자열 제거, 찾기 및 바꾸기 기능을 살펴 보았지만 위치에 따라 작동한다는 것만 알 수 있습니다.

예를 들어 "("문자를 전달하고 문자열 내의 모든 인스턴스를 제거하는 데 사용할 수있는 문자열 함수가 있습니까?

답변:


140
   string str("(555) 555-5555");

   char chars[] = "()-";

   for (unsigned int i = 0; i < strlen(chars); ++i)
   {
      // you need include <algorithm> to use general algorithms like std::remove()
      str.erase (std::remove(str.begin(), str.end(), chars[i]), str.end());
   }

   // output: 555 5555555
   cout << str << endl;

기능으로 사용하려면 :

void removeCharsFromString( string &str, char* charsToRemove ) {
   for ( unsigned int i = 0; i < strlen(charsToRemove); ++i ) {
      str.erase( remove(str.begin(), str.end(), charsToRemove[i]), str.end() );
   }
}
//example of usage:
removeCharsFromString( str, "()-" );

4
어떻게 작동합니까? 지우기 및 제거를 사용하는 것이 이중 부정이 아닙니까? 나에게 이것은 "()가없는 위치에있는 문자를 지우십시오."라고 읽습니다. 그리고 한 번에 하나씩 수행되므로 모든 문자를 제거해야하지 않습니까? 나는 두 기능에 대한 문서를 읽었으며 이것은 나에게 의미가 없습니다. cplusplus.com/reference/algorithm/remove cplusplus.com/reference/string/string/erase
Brent '

@Brent std :: remove ()는 문자열에서 유효한 문자를 제거하지 않고 유효한 문자를 함께 이동합니다.
lk_vc 2013

20
@Brent와 미래 독자 여러분, 이것은 Erase-remove 관용구 입니다. 간단히 말해서, std::remove제거되지 않은 항목을 벡터 앞쪽으로 이동하고 제거되지 않은 마지막 항목 바로 너머를 가리키는 반복자를 반환합니다. 그런 다음 std::erase해당 반복기에서 끝까지 벡터를 트리밍합니다.
chwarr

1
정말 C ++ 버전의 경우 문자에 액세스 할 수있는 길이와 방법을 얻기 string chars("()-");위해 .length()메소드를 사용 하고 사용해야한다고 생각합니다. .at(i):) Functionized fiddle-ideone.com/tAZt5I
jave.web

2
로 사용하려면 : 기능 ideone.com/XOROjq 사용 -<iostream> <algorithm> <cstring>
jave.web

36

문자열에서 "(", ")"및 "-"문자를 제거하고 싶습니다.

std::remove_if()알고리즘을 사용하여 지정한 문자 만 제거 할 수 있습니다 .

#include <iostream>
#include <algorithm>
#include <string>

bool IsParenthesesOrDash(char c)
{
    switch(c)
    {
    case '(':
    case ')':
    case '-':
        return true;
    default:
        return false;
    }
}

int main()
{
    std::string str("(555) 555-5555");
    str.erase(std::remove_if(str.begin(), str.end(), &IsParenthesesOrDash), str.end());
    std::cout << str << std::endl; // Expected output: 555 5555555
}

std::remove_if()알고리즘은 위의 조각 같은 함수 포인터가 될 수있는 조건이라는 것을 필요로한다.

함수 객체 (함수 호출 ()연산자 를 오버로드하는 객체)를 전달할 수도 있습니다 . 이를 통해 훨씬 더 일반적인 솔루션을 만들 수 있습니다.

#include <iostream>
#include <algorithm>
#include <string>

class IsChars
{
public:
    IsChars(const char* charsToRemove) : chars(charsToRemove) {};

    bool operator()(char c)
    {
        for(const char* testChar = chars; *testChar != 0; ++testChar)
        {
            if(*testChar == c) { return true; }
        }
        return false;
    }

private:
    const char* chars;
};

int main()
{
    std::string str("(555) 555-5555");
    str.erase(std::remove_if(str.begin(), str.end(), IsChars("()- ")), str.end());
    std::cout << str << std::endl; // Expected output: 5555555555
}

"()- "문자열 로 제거 할 문자를 지정할 수 있습니다 . 위의 예에서는 괄호와 대시뿐만 아니라 공백도 제거되도록 공백을 추가했습니다.


당신은 또한 사용할 수 있습니다ispunct(int c)
MSalters

뛰어난 구현. 이 방법은 완벽하게 작동했으며 추가 역학을위한 여지가 많습니다. 응답 해 주셔서 감사합니다. MSalters, 나는 또한 ispunct (int c) 함수를 찾고 내 작업에 대해보고 할 것입니다.
SD.

12

remove_if ()는 이미 언급되었습니다. 그러나 C ++ 0x에서는 대신 람다를 사용하여 조건자를 지정할 수 있습니다.

다음은 필터링을 수행하는 3 가지 방법의 예입니다. const로 작업하거나 원본을 수정하지 않으려는 경우를 위해 함수의 "복사"버전도 포함됩니다.

#include <iostream>
#include <string>
#include <algorithm>
#include <cctype>
using namespace std;

string& remove_chars(string& s, const string& chars) {
    s.erase(remove_if(s.begin(), s.end(), [&chars](const char& c) {
        return chars.find(c) != string::npos;
    }), s.end());
    return s;
}
string remove_chars_copy(string s, const string& chars) {
    return remove_chars(s, chars);
}

string& remove_nondigit(string& s) {
    s.erase(remove_if(s.begin(), s.end(), [](const char& c) {
        return !isdigit(c);
    }), s.end());
    return s;
}
string remove_nondigit_copy(string s) {
    return remove_nondigit(s);
}

string& remove_chars_if_not(string& s, const string& allowed) {
    s.erase(remove_if(s.begin(), s.end(), [&allowed](const char& c) {
        return allowed.find(c) == string::npos;
    }), s.end());
    return s;
}
string remove_chars_if_not_copy(string s, const string& allowed) {
    return remove_chars_if_not(s, allowed);
}

int main() {
    const string test1("(555) 555-5555");
    string test2(test1);
    string test3(test1);
    string test4(test1);
    cout << remove_chars_copy(test1, "()- ") << endl;
    cout << remove_chars(test2, "()- ") << endl;
    cout << remove_nondigit_copy(test1) << endl;
    cout << remove_nondigit(test3) << endl;
    cout << remove_chars_if_not_copy(test1, "0123456789") << endl;
    cout << remove_chars_if_not(test4, "0123456789") << endl;
}

const char & c 대신 실제로 const string :: value_type &을 사용해야합니다. 그러나이 경우에는 큰 문제가 아닙니다.
Shadow2531 2011

1
이것은 매우 철저한 구현입니다. 감사합니다.이 구현도 사용할 것입니다.
SD.

8

관심있는 사람을위한 다른 솔루션이 있습니다. C ++ 11에서 새로운 For 범위를 사용합니다.

string str("(555) 555-5555");
string str2="";

for (const auto c: str){

    if(!ispunct(c)){

        str2.push_back(c);
    }
}

str = str2;
//output: 555 5555555
cout<<str<<endl;

1
(1) str2초기화가 필요하지 않습니다. (2) str = std::move(str2)더 효율적입니다.
Ajay

6

std :: string에 대한 그러한 멤버가없는 것이 두렵습니다.하지만 이러한 종류의 함수를 쉽게 프로그래밍 할 수 있습니다. 가장 빠른 솔루션은 아니지만 이것으로 충분합니다.

std::string RemoveChars(const std::string& source, const std::string& chars) {
   std::string result="";
   for (unsigned int i=0; i<source.length(); i++) {
      bool foundany=false;
      for (unsigned int j=0; j<chars.length() && !foundany; j++) {
         foundany=(source[i]==chars[j]);
      }
      if (!foundany) {
         result+=source[i];
      }
   }
   return result;
}

편집 : 아래 답변을 읽으면서 숫자를 감지하는 것뿐만 아니라 더 일반적으로 이해했습니다. 위의 솔루션은 두 번째 인수 문자열에 전달 된 모든 문자를 생략합니다. 예를 들면 :

std::string result=RemoveChars("(999)99-8765-43.87", "()-");

결과는

99999876543.87

3
using namespace std;


// c++03
string s = "(555) 555-5555";
s.erase(remove_if(s.begin(), s.end(), not1(ptr_fun(::isdigit))), s.end());

// c++11
s.erase(remove_if(s.begin(), s.end(), ptr_fun(::ispunct)), s.end());

참고 :ptr_fun<int, int> 간단하지 않고 쓰기 가 필요할 수 있습니다.ptr_fun


이것이 어떻게 선택된 답이 아닌가?
user3240688

@ user3240688 std :: ptr_fun 은 C ++ 11에서 더 이상 사용되지 않으며 C ++ 17에서 제거되고 std :: not1 은 C ++ 17에서 더 이상 사용되지 않습니다. std::cref또는 std::function(또는 람다)를 사용할 수 있습니다 .
Roi Danton

3

예, isdigit () 함수를 사용하여 숫자를 확인할 수 있습니다. :)

여기 있습니다 :

#include <iostream>
#include <cctype>
#include <string.h>

using namespace std;

int main(){

  char *str = "(555) 555-5555";
  int len = strlen(str);

  for (int i=0; i<len; i++){
      if (isdigit(*(str+i))){
        cout << *(str+i);
      }
  }

  cout << endl;


return 0;   
}

도움이되기를 바랍니다 :)


false를 반환하는 요소를 제거하도록 수정할 수 있습니다. 감사합니다.
SD.

3

boost::is_any_of

주어진 다른 문자열에 나타나는 하나의 문자열에서 모든 문자를 제거합니다.

#include <cassert>

#include <boost/range/algorithm/remove_if.hpp>
#include <boost/algorithm/string/classification.hpp>

int main() {
    std::string str = "a_bc0_d";
    str.erase(boost::remove_if(str, boost::is_any_of("_0")), str.end());
    assert((str == "abcd"));
}

Ubuntu 16.04, Boost 1.58에서 테스트되었습니다.


2

가변 템플릿을 지원하는 컴파일러에 액세스 할 수있는 경우 다음을 사용할 수 있습니다.

#include <iostream>
#include <string>
#include <algorithm>

template<char ... CharacterList>
inline bool check_characters(char c) {
    char match_characters[sizeof...(CharacterList)] = { CharacterList... };
    for(int i = 0; i < sizeof...(CharacterList); ++i) {
        if(c == match_characters[i]) {
            return true;
        }
    }
    return false;
}

template<char ... CharacterList>
inline void strip_characters(std::string & str) {
    str.erase(std::remove_if(str.begin(), str.end(), &check_characters<CharacterList...>), str.end());
}

int main()
{
    std::string str("(555) 555-5555");
    strip_characters< '(',')','-' >(str);
    std::cout << str << std::endl;
}

1

또 다른 대안이 있습니다.

template<typename T>
void Remove( std::basic_string<T> & Str, const T * CharsToRemove )
{
    std::basic_string<T>::size_type pos = 0;
    while (( pos = Str.find_first_of( CharsToRemove, pos )) != std::basic_string<T>::npos )
    {
        Str.erase( pos, 1 ); 
    }
}

std::string a ("(555) 555-5555");
Remove( a, "()-");

std :: string 및 std :: wstring과 함께 작동합니다.


1

나는 처음이지만 위의 답변 중 일부는 엄청나게 복잡하므로 여기에 대안이 있습니다.

참고 : 0-9가 연속적이면 (표준에 따라야 함) 숫자와 ''를 제외한 다른 모든 문자를 필터링해야합니다. 0-9가 연속적이어야하고 char이 실제로 int라는 것을 알면 아래와 같이 할 수 있습니다.

편집 : 포스터도 공간을 원한다는 것을 알지 못했기 때문에 변경했습니다 ...

#include <cstdio>
#include <cstring>

void numfilter(char * buff, const char * string)
{
  do
  { // According to standard, 0-9 should be contiguous in system int value.
    if ( (*string >= '0' && *string <= '9') || *string == ' ')
      *buff++ = *string;
  } while ( *++string );
  *buff++ = '\0'; // Null terminate
}

int main()
{
  const char *string = "(555) 555-5555";
  char buff[ strlen(string) + 1 ];

  numfilter(buff, string);
  printf("%s\n", buff);

return 0;
}

아래는 제공된 문자를 필터링하는 것입니다.

#include <cstdio>
#include <cstring>

void cfilter(char * buff, const char * string, const char * toks)
{
  const char * tmp;  // So we can keep toks pointer addr.
  do
  {
    tmp = toks;
    *buff++ = *string; // Assume it's correct and place it.
    do                 // I can't think of a faster way.
    {
      if (*string == *tmp)
      {
        buff--;  // Not correct, pull back and move on.
        break;
      }
    }while (*++tmp);
  }while (*++string);

  *buff++ = '\0';  // Null terminate
}

int main()
{
  char * string = "(555) 555-5555";
  char * toks = "()-";
  char buff[ strlen(string) + 1 ];

  cfilter(buff, string, toks);
  printf("%s\n", buff);

  return 0;
}

그것은 OP가 원하는 것을하지 않습니다. 공백도 삭제합니다.
Andrew Barber

1

사용하여 표준 : : wstring의wchar_t를하는 것은 합니다 (필요 유니 코드 헤더) :

//#include <tchar.h>
std::wstring phone(L"(555) 555-5555");

... 멋진 정적 범위 이니셜 라이저 다음; 똑같은 방식으로 badChars2를 설정할 필요가 없습니다. 과잉입니다. 무엇보다 학문적 :

const wchar_t *tmp = L"()-"; 
const std::set<wchar_t> badChars2(tmp,tmp + sizeof(tmp)-1);

간단하고 간결한 람다 :

  1. 람다 캡처 목록에서 전화 를 사용 합니다.
  2. 사용 지우기 - 제거 관용구
  3. 전화 에서 모든 잘못된 문자를 제거합니다.

    for_each(badChars2.begin(), badChars2.end(), [&phone](wchar_t n){
         phone.erase(std::remove(phone.begin(), phone.end(), n), phone.end());
    });
    wcout << phone << endl;

출력 : "555 5555555"


1

보다 간결하고 읽기 쉬운 람다 코딩 스타일을 선호하는 분들을 위해 ...

이 예에서는 넓은 문자열에서 영숫자가 아닌 모든 공백 문자를 제거합니다. 복잡한 모양의 문자 기반 테스트를 제거하기 위해 다른 ctype.h 도우미 함수 와 혼합 할 수 있습니다 .

(이 함수가 CJK 언어를 어떻게 처리할지 잘 모르겠으므로 부드럽게 걸어가십시오.)

    // Boring C loops: 'for(int i=0;i<str.size();i++)' 
    // Boring C++ eqivalent: 'for(iterator iter=c.begin; iter != c.end; ++iter)'

시끄러운 C / C ++ for / iterator 루프보다 이해하기가 더 쉽지 않은지 확인하십시오.

TSTRING label = _T("1.   Replen & Move  RPMV");
TSTRING newLabel = label;
set<TCHAR> badChars; // Use ispunct, isalpha, isdigit, et.al. (lambda version, with capture list parameter(s) example; handiest thing since sliced bread)
for_each(label.begin(), label.end(), [&badChars](TCHAR n){
    if (!isalpha(n) && !isdigit(n))
        badChars.insert(n);
});

for_each(badChars.begin(), badChars.end(), [&newLabel](TCHAR n){
    newLabel.erase(std::remove(newLabel.begin(), newLabel.end(), n), newLabel.end());
});

이 코드를 실행 한 후 newLabel 결과 : " 1ReplenMoveRPMV "

분명히 lambda0 (첫번째에서 '만약'논리를 결합하는 것이 더 정확 간결하고 효율적 것이기 때문에, 단지 학문적 인 의 for_each 단일 lambda1 (둘째로) 의 for_each 이미 설정 한 경우 "badChars는"있는 자) .


편리한 Erase-remove 관용구를 언급하고 사용하는 @Eric Z의 답변에 감사드립니다. en.wikipedia.org/wiki/Erase-remove_idiom
Darrin

0

많은 좋은 대답이 있습니다. 여기에 숫자 문자열을 정리하는 또 다른 방법은 문자를 삭제하는 것이 아니라 숫자를 제거하는 것입니다.

string str("(555) 555-5555"), clean;
for (char c : str)
    if (c >= 48 and c <= 57)
        clean.push_back(c);
당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.