티스토리 뷰

이 글은 <string> library  대해 다루겠습니다. 공부한 것을 정리하는 형식으로 작성되었으므로 오류가 있을 수 있습니다. 오류 발견시 댓글로 꼭 말씀해주세요! 시작해볼까요?

계획에 따라 '구현'을 하는 것이 알고리즘 문제 풀이의 핵심이라고 하지만 얼마나 효율적으로 잘 하느냐도 중요합니다. 사용할 주력 언어를 정했으면 그 언어가 지원하는 library에 대해 잘 아는 것도 매우 중요합니다. 그래서 이번 글에서는 정말 많이 쓰는 #include <string> 을 하게 되면 무엇을 할 수 있고, 어떻게 활용할 수 있는지 살펴보겠습니다. 나와 있는 순서는 제가 많이 사용하는 함수들, 구분선 뒤로는 아직 문제를 풀다가 사용해본 경험은 없는 함수들 입니다.

정말 많이 쓰고 있는 함수

1. size / length / max_size

size 또는 length는 for 문에서 종료 조건에 많이 씁니다. for(int i = 0; i < str.length(); i++) 처럼 많이쓰는데, 저는 size 보다는 length를 씁니다. str.size()와 str.length()가 같은 값을 반환하기 때문에 구분 없이 사용하기도 하는데 두 function은 명확히 다릅니다.

  • str.size() 는 실제 사용되고 있는 크기를 반환
  • str.length()는 문자열의 길이를 반환
  • ( str.max_size()는 문자열이 최대로 가질 수 있는 길이를 반환 )

그래서 문자열의 길이와 관련된 작업을 하고 싶으시다면 length를, 메모리 공간과 관련된 작업을 하신다면 size를 쓰면 됩니다.

2. find

주어진 문자열에서 특정 문자열을 찾고 그 시작 위치를 반환하는 함수로, 문제 풀이를 할 때 substr()과 함께 많이 쓰이는 함수입니다. 사용할 수 있는 방법은 2가지 입니다. 첫번째 방법은 막연히 한 문자열에서 다른 문자/문자열을 찾을 때, 두번째 방법은 binary search나 recursion을 통해(하나의 예시일 뿐 100% 이런 경우에 쓴다는 것은 아닙니다.) 찾고자 하는 문자열의 시작 위치 범위를 점차 좁혀나가서 대충 시작 위치를 알 때입니다.

  • str1.find(str2) : 문자열의 시작부터 해당 문자/문자열을 찾고 그 시작 위치를 반환
  • str1.find(str2, pos) : 매개 변수(pos)로 주어진 시작 위치부터 문자열을 찾고 그 시작 위치를 반환

find함수의 큰 특징 중 하나는 찾고자 하는 문자열을 찾지 못한다면 -1 또는 음수값을 반환하는 것이 아닌 unsigned long int가 담지 못하는 큰 수를 반환한다는 것입니다. (find 의 return type이 unsigned long int입니다)

이 모든 것들을 문제에서 어떻게 활용할 수 있는지 알아보기 위해 SWEA의 [S/W 문제해결 기본] 3일차 - String 문제를 풀어보겠습니다.

문제와 제약조건을 직접 보고 싶으신 분들은 위 링크를 따라 가보시면 되고, 귀찮으시면 아래 더보기를 눌러주세요.

더보기

[입력]
총 10개의 테스트 케이스가 주어지며 각 테스트 케이스의 첫 줄에는 테스트 케이스의 번호가 주어진다. 그 다음 줄에는 찾을 문자열, 그 다음 줄에는 검색할 문장이 주어진다. 단 문장의 길이는 1000자를 넘어가지 않고 한 문장에서 검색하는 문자열의 길이는 최대 10을 넘지 않는다.

주어지는 영어 문장에서 특정한 문자열의 개수를 반환하는 프로그램을 작성하여라.

Starteatingwellwiththeseeighttipsforhealthyeating,whichcoverthebasicsofahealthydietandgoodnutrition.

위 문장에서 ti 를 검색하면, 답은 4이다.

[입력]
총 10개의 테스트 케이스가 주어지며 각 테스트 케이스의 첫 줄에는 테스트 케이스의 번호가 주어진다. 그 다음 줄에는 찾을 문자열, 그 다음 줄에는 검색할 문장이 주어진다. 단 문장의 길이는 1000자를 넘어가지 않고 한 문장에서 검색하는 문자열의 길이는 최대 10을 넘지 않는다.

loc을 찾고 given = given.substr(loc + toFind.length()) 로 수정해나가는 과정

아래 그림을 통해 풀이를 어떻게 설계하면 되는지 살표보도록 하겠습니다. GIVEN은 처음에 주어진 문자열을 담고 있지만 원하는 문자열을 찾을 때마다 조금씩 조금씩 짧아질 예정입니다. toFind는 GIVEN 문자열에서 찾아야 하는 문자열로 아래 그림 예시의 경우 'EF'가 됩니다.

find 함수는 문자열을 찾고 그 시작 위치를 반환하므로 GIVEN 내에서 find() 함수를 통해 toFind를 찾고 GIVEN에서 찾은 문자열 앞부분은 잘라냅니다

위에서도 간략히 설명을 했지만 조금 더해서 설명하자면

  • toFind : 찾아야 할 문자열
  • given : 주어진 문자열
  • inSearch : 계속 탐색을 해야하는지를 판별하기 위한 bool 변수
  • loc
    • 역할 1 : find 함수를 썼을 때 찾고자 하는 문자열의 시작 위치 반환값 저장
    • 역할 2 : 반환 여부 자체를 판별 - 문자열의 길이보다 큰 숫자를 반환받으면 찾지 못했음을 의미
  • cnt : 최종 문제의 답으로, 주어진 문자열이 총 몇 번 쓰였는지 count 하는 변수

이 문제는 단순히 찾고자 하는 문자열이 있나, 없나의 여부를 따지는 것이 아니라 몇 번 등장하는지를 묻습니다. 그러므로 given이 저장하고 있는 문자열을 계속 수정해나가야 풀 수 있습니다. 그리고 그 수정과정에서 substr이 중요한 역할을 하는데, substr과 관련된 내용은 바로 아래에 쓰겠습니다. 코드 복사를 희망하시는 분들은 더보기를 펼치시면 됩니다.

더보기
#include <iostream>
#include <string>

using namespace std;

int main(void){
    for(int test = 1; test <= 10; test++){
        int testCase;
        string toFind, given;
        cin >> testCase >> toFind >> given;
        bool inSearch = true;
        unsigned long int loc = -1;
        int cnt = 0;
        while(inSearch){
            loc = given.find(toFind);
            if(loc < given.length()){
                given = given.substr(loc + toFind.length());
                cnt++;
            }
            else
                inSearch = false;
        }
        cout << "#" << test << " " << cnt << endl;
    }

}

 

3. substr

문자열의 일부분을 추출하는 함수로 문자열이 문제의 핵심이라면 거의 무조건 쓰게 되어 있는 함수라고 해도 과언이 아닌 것 같습니다.

사용 방법은 총 2가지인데 상황에 따라 2가지 모두 사용하게 되므로 2가지 모두 알고 계셔야 합니다.

  • str.substr(pos) : pos의 위치부터 끝까지를 추출
  • str.substr(pos, num) : pos 위치부터 num 개수 만큼 추출
string str = “ABCDEF”;
string str2 = s.substr(4); // str2 = “EF”
string str3 = s.substr(1, 3) // str3 = “BCD”

위에서 살펴본 SWEA 문제에서 given = given.substr( loc + toFind.length( ) ) 라고 쓴 것의 의미는 아래와 같습니다.

 : toFind에 해당되는 문자열이 발견되고, 해당 문자열 이후의 지점부터 끝까지를 추출하여 given에 저장.

4. compare

문자열을 사전 순으로 비교하는 함수로 비교하는 두 문자열이 같으면 0, strA < strB이면 음수, strA > strB 이면 양수를 반환합니다.

int com = strA.compare(strB) 처럼 사용하는 함수입니다.

간혹 compare 함수가 생각이 나지 않아 C 언어 때 사용하던 strcmp가 떠오를 때가 많습니다.

쓸 수 있지 않을까... 싶다가 검색해보면 아니나 다를까 compare가 뜹니다.

네... compare 씁시다ㅋㅋ 


사용해본 적 없는 함수

1. assign

문자열의 할당을 위해 assign이라는 함수를 사용하는데, append 라는 함수보다 string s = "asdf" 식으로 더 자주하는 것 같습니다.

3번째에 str3.assign(str1, pos, num)는 substr( )으로도 사용이 가능하니 굳이 복잡하게 더 많은 함수를 알아야 하나 싶습니다.

  • str1.assign(str) : str1에 str을 할당 → str1 = str이라고 하면 되겠죠?
  • str2.assign(num, char) : str2에 char를 num만큼 할당 → 어떤 문자가 몇번 들어가는지 알면 str = "XXX" 하면 되겠죠?
  • str3.assign(문자열, 시작 위치, 갯수) : 매개변수로 주어진 문자열의 시작위치부터 개수만큼 할당 → str3 = str.substr(2, 4) 
string str1, str2, str3;
str1.assign(“ABCDEFGH”); // str1 = ABCDEFGH
str2.assign(3, ‘X’) // str2 = XXX
str3.assign(str1, 2, 4); // str3 = CDEF

2. append

문자열의 끝에 문자 또는 문자열을 더하는 함수로 '+' operator로 충분히 대체 가능해서 한 번도 사용해본 적이 없는 함수입니다.

  • str1.append(str) : 기존 문자열 str1에 str을 뒤에 더함 → str1 += str
  • str1.append(num, char) : char를 num만큼 끝에 더함 → str1 += "XXX"
  • str2.(str, pos, num) : str의 시작위치부터 개수만큼 str2의 끝에 더함 → str2 += str.substr(0, 4)
string str1 = "ABCDE";
str1.append("FGH"); // str1 = “ABCDEFGH
str1.append(3, 'x'); // str1 = “ABCDEFGHxxx”

string str2 = "XXX";
str2.append(s, 0, 4); // str2 = “XXXABCD”

 

3. clear / erase

문자열의 내용을 지우고 싶다면 str = "" (빈 문자열) 를 많이 사용했지 개인적으로 함수를 따로 쓴 경험은 없습니다.

  • str.clear() : 문자열의 내용을 모두 삭제
  • str.erase(pos, num) : 기존 문자열의 pos부터 num만큼의 문자를 지움
string str = “ABCDEF”
str.erase(0, 3) // str = “DEF” 0번째부터 3개를 지움

 

4. empty

문자열이 비어있는지 확인하는 함수로, str.length() == 0 임을 뜻하는 것이므로 대체할 수 있을 것 같습니다.

 

5. replace : 문자열을 대체

  • str.(시작 위치, 갯수, 문자열) : str의 시작 위치 부터 주어진 갯수만큼의 문자를 매개변수로 주어진 문자열로 대체
string str = “abc_def”;
str.replace(4, 3, “zzz”); //str = “abc_zzz” (인덱스 4부터 3개의 문자를 “zzz”로 대체)

6. insert : 문자열을 저장한 위치에 삽입

  • str.(시작 위치, 문자열) : 주어진 시작 위치 이후로 매개변수로 주어지는 문자열 삽입

string str = “ABC”;
str.insert(2, “xx”); // str = “ABxxC”

7. pop_back / push_back

  • str.pop_back() : str에서 맨 뒤의 문자 하나를 빼냄 → char c = str[str.size() - 1]; str = str.substr(1);
  • str.push_back() : str에서 맨 뒤에 문자를 하나 추가함 → str  += "x"
string str = “ABCDEF”;
str.pop_back(); // str = “ABCDE”
str.push_back(‘x’); // str = “ABCDEx”

 

8.resize : 문자열의 크기를 재설정

9. capacity : 할당된 메모리의 크기를 반환 (reallocation 없이 사용할 수 있는 문자수를 반환)

  • capacity > size 일 때 속도는 더 빠르다
  • capacity가 더 크면 문자를 추가하는 작업만 이루어지면 되지만 size가 더 클 경우에는 문자를 추가하기 위해 새로운 메모리 공간을 할당해야 하기 때문이다.
string s = “ABCDEF”;
int capacity = s.capacity(); // size = 6, capacity = 15

 

10. reserve : reallocation을 피하기 위해, 메모리의 최소용량을 지정

  • str.(size) : size만큼의 여유 메모리를 할당합니다. 이때 size의 크기가 현재 capacity보다 작으면 의미도 효과도 없습니다.

string str = “ABCDEF”; // size = 6, capacity = 15
str.reserve(100); // size = 6, capacity = 111
str.reverse(1000); // size = 6, capacity = 1007

11. swap : 문자열을 서로 바꾸는 함수

string a = “ABCD”;
string b = “WXYZ”;
a.swap(b); // a = “WXYZ”, b = “ABCD”

12. at

문자열 특정 위치의 문자에 접근하기 위해 at이라는 함수가 있지만 저는 그냥 인덱스로 찾습니다.

 

댓글
공지사항
최근에 올라온 글
최근에 달린 댓글
Total
Today
Yesterday
링크
«   2025/01   »
1 2 3 4
5 6 7 8 9 10 11
12 13 14 15 16 17 18
19 20 21 22 23 24 25
26 27 28 29 30 31
글 보관함