remove(), string::erase 함수
출처 : https://www.cplusplus.com/
1. function template std::remove
template <class ForwardIterator, class T>
ForwardIterator remove (ForwardIterator first, ForwardIterator last, const T& val);
이 함수는 #include < algorithm > 헤더에 있는 remove이다. 파일명을 확인해서 파일을 제거하는 remove 함수는 cstdio 헤더파일에 포함되어 있다.
구성은 단순하다. 첫번째와 두번째 파라미터로 삭제할 범위의 이터레이터를 넣으면 된다. 이터레이터의 특징은 범위가 [first, last) 즉 first 이상 last 미만이라는 점이다.
세번째 파라미터는 이터레이터를 돌며 삭제할 값이다.
반환값으로 제거되지 않은 마지막 원소의 이터레이터(쉽게 여기선 위치라고 생각하자)를 반환한다고 되어 있다.
예제
#include <iostream>
#include <string>
#include <algorithm>
using namespace std;
int main()
{
string str1;
getline(cin, str1);
remove(str1.begin(), str1.end(), ' ');
for (string::iterator it = str1.begin(); it != str1.end(); ++it)
cout << *it;
cout << endl;
return 0;
}
결과
- 위 코드에서는 입력받은 str1에서 스페이스 ‘ ‘를 제거하는 코드이다.
- 키보드를 통해 for ever young을 입력했다.(빨간색 check는 스페이스를 표현한 것이다)
- 결과값이 이상하다. for ever young에서 space를 제거하면 foreveryoung이 나올 줄 알았는데 foreveryoungng라고 뒤에 ng가 더 있음을 알 수 있다.
- 일반적으로 STL의 컨테이너들이 가지고 있는 remove 함수와 다르게 이 remove 함수는 작동방식이 다르다. 함수 호출시 3번째 인자로 넘어온 값(여기선 스페이스)와 같은 값을 찾고 찾은 값(여기선 스페이스)의 다음 요소(여기선 문자)부터 마지막 요소까지 모두 한칸 앞으로 카피하는 방식으로 작동하기 때문이다.
- 즉 for ever young에서 r 다음에 있는 스페이스를 발견하고 그 뒤에 있는 e부터 young의 g까지 전부 한칸씩 앞으로 복사하다 보니 마지막에 있던 ng도 출력된다.
2. std::string::erase
sequence (1)
string& erase (size_t pos = 0, size_t len = npos);
character (2)
iterator erase (const_iterator p);
range (3)
iterator erase (const_iterator first, const_iterator last);
- 이 erase 함수는 string 클래스에 있는 public 멤버함수이다.
- erase하는 방법은 총 3가지가 있다.
// string::erase
#include <iostream>
#include <string>
int main ()
{
std::string str ("This is an example sentence.");
std::cout << str << '\n';
// "This is an example sentence."
str.erase (10,8); // ^^^^^^^^
std::cout << str << '\n';
// "This is an sentence."
str.erase (str.begin()+9); // ^
std::cout << str << '\n';
// "This is a sentence."
str.erase (str.begin()+5, str.end()-9); // ^^^^^
std::cout << str << '\n';
// "This sentence."
return 0;
}
첫번째 방법은, 기준점(pos)을 넣고 기준점으로부터 몇개의 문자들을 지울지 적는 것이다. string 컨테이너도 시퀀스 컨테이너이며 배열 기반 컨테이너 범주에 속한다. 따라서 배열의 index가 0부터 시작하듯이 string을 이용한 문자열도 맨 앞이 0부터 시작한다. 위 코드에서 str.erase (10,8); 를 통해 기준점이 10(맨 앞이 0이므로 사실상 11번째)인 문자부터 8개를 지운다고 되어 있다. T가 기준점이 0인 곳이고 example의 e앞의 스페이스가 10인 곳이다. 기준점으로부터 카운트 할 때 스페이스도 포함해야 한다. 스페이스 + example이 10, 11, 12, 13, 14, 15, 16, 17이 총 8개이므로 example이 erase된다.
두번째 방법은, 이터레이터를 사용해서 특정 지점을 지정하는 것이다. 위 코드에서 str.erase (str.begin()+9); 를 사용해 맨 처음에서 9번째에 있는 문자를 지정했다.
세번째 방법으로 이터레이터를 사용해서 범위를 지정하는 방법이다.
3. remove()와 std::string::erase 같이 쓰기
예제
#include <iostream>
#include <string>
#include <algorithm>
using namespace std;
int main()
{
string str1;
getline(cin, str1);
str1.erase(remove(str1.begin(), str1.end(), ' '), str1.end());
for (string::iterator it = str1.begin(); it != str1.end(); ++it)
cout << *it;
cout << endl;
return 0;
}
결과
- 1번에서 단순 remove() 함수를 이용해서 스페이스를 제거했을시 foreveryoungng이란 문제가 발생했다. 하지만 remove와 erase 함수를 활용하면 이런 문제점을 해결 할 수 있다.
remove() 함수는 제거하지 않은(움직이지 않은) 마지막 원소의 이터레이터(위치)를 반환한다.
- 위의 for ever young 예시에서
for ever young
foreveryoungng
youngng에서 두 번째 n의 위치를 이터레이터로 반환한다. erase 함수는 두 번째 n부터 str1.end()까지 글자를 삭제하므로 따라서 ng가 삭제되고 출력은 원했던 foreveryoung으로 나오게 된다.
4. anagram 함수 만들때 2
bool IsAnagram(string str1, string str2)
{
transform(str1.begin(), str1.end(), str1.begin(), toupper);
transform(str2.begin(), str2.end(), str2.begin(), toupper);
str1.erase(remove(str1.begin(), str1.end(), ' '), str1.end());
str2.erase(remove(str2.begin(), str2.end(), ' '), str2.end());
}
–> 이런 식으로 anagram을 판별하는 함수를 만들 수 있다. transform을 활용해서 전부 문자열을 전부 대문자로 바꾼후에 erase와 remove 함수를 활용하여 문자열 사이에 스페이스를 제거하는 방식이다. 그후에 std::sort 함수를 이용하여 문자열을 크기 순(아스키 코드상 값 순)으로 바꾼 후에 비교하면 두 문자열이 anagram인지 아닌지 알 수 있다.