본문 바로가기

Algorithm/PS

[PS] getline함수 간단하게 보기

개요

해당 카테고리에서는 코딩 문제를 풀 때 사용했던 간단한 방법에 대해 알아보겠다.

 

사실 대부분 검색하면 바로 나올정도로 간단한 내용들이지만, 실제 코딩 테스트 등에서 인터넷 검색을 허락하지 않기 때문에 방법을 외울 필요도 있다.

 

따라서 외울 겸 정리하겠다. (매우 간단하게)  (C++ 문법에 따라)

 

이번에는 getline함수에 대해 알아보겠다.


getline

getline함수는 std namespace에 있는 함수이다.

입력 스트림을 읽어 문자열을 추출하는 함수이다.

_EXPORT_STD template <class _Elem, class _Traits, class _Alloc>
basic_istream<_Elem, _Traits>& getline(
    basic_istream<_Elem, _Traits>&& _Istr, basic_string<_Elem, _Traits, _Alloc>& _Str, const _Elem _Delim) {
    // get characters into string, discard delimiter
    using _Myis = basic_istream<_Elem, _Traits>;

    typename _Myis::iostate _State = _Myis::goodbit;
    bool _Changed                  = false;
    const typename _Myis::sentry _Ok(_Istr, true);

    if (_Ok) { // state okay, extract characters
        _TRY_IO_BEGIN
        _Str.erase();
        const typename _Traits::int_type _Metadelim = _Traits::to_int_type(_Delim);
        typename _Traits::int_type _Meta            = _Istr.rdbuf()->sgetc();

        for (;; _Meta = _Istr.rdbuf()->snextc()) {
            if (_Traits::eq_int_type(_Traits::eof(), _Meta)) { // end of file, quit
                _State |= _Myis::eofbit;
                break;
            } else if (_Traits::eq_int_type(_Meta, _Metadelim)) { // got a delimiter, discard it and quit
                _Changed = true;
                _Istr.rdbuf()->sbumpc();
                break;
            } else if (_Str.max_size() <= _Str.size()) { // string too large, quit
                _State |= _Myis::failbit;
                break;
            } else { // got a character, add it to string
                _Str += _Traits::to_char_type(_Meta);
                _Changed = true;
            }
        }
        _CATCH_IO_(_Myis, _Istr)
    }

    if (!_Changed) {
        _State |= _Myis::failbit;
    }

    _Istr.setstate(_State);
    return static_cast<basic_istream<_Elem, _Traits>&>(_Istr);
}

위의 코드가 실제 string 헤더 내에 있는 getline함수이다.

 

보면 3개의 인자 stream, string, 구분자를 받는 것을 알 수 있다.

 

간단히 정리하자면, stream이 유효한지 확인하고, 구분자 이전까지의 값을 string에 넣는 것이다.


기본적으로 getline(cin, line); 이와 같은 형태로 알고리즘 문제에서는 사용한다.

2개 인자를 받는 함수도 보겠다.

_EXPORT_STD template <class _Elem, class _Traits, class _Alloc>
basic_istream<_Elem, _Traits>& getline(
    basic_istream<_Elem, _Traits>& _Istr, basic_string<_Elem, _Traits, _Alloc>& _Str) {
    // get characters into string, discard newline
    return _STD getline(_STD move(_Istr), _Str, _Istr.widen('\n'));
}

 

이를 보면 구분자를 '\n'으로 하여 3개인자 getline에 넘겨주고 있음을 볼 수 있다.

 


반환 값으로는 사용한 스트림의 참조를 돌려줍니다. 

실패한 경우 fail을 반환한다.

 

이 때 해당 반환 값을 bool로 변환하면 fail은 false, 나머지는 true이기 때문에 이를 통해 파싱을 시도해볼 수 있다.


https://www.acmicpc.net/problem/22233

이러한 방법을 사용하는 간단한 문제이다.

 

#include <iostream>
#include <vector>
#include <string>
#include <sstream>
#include <algorithm>
#include <unordered_set>
using namespace std;

int main() {
    ios::sync_with_stdio(false);
    cin.tie(nullptr);

    int N, M;
    cin >> N >> M;

    unordered_set<string> memo;
    memo.reserve(N);

    for (int i = 0; i < N; ++i)
    {
        string keyword;
        cin >> keyword;
        memo.insert(move(keyword));
    }

    cin.ignore();
    ostringstream oss;
    for (int i = 0; i < M; ++i)
    {
        string line;
        getline(cin, line);
        stringstream ss(line);

        string keyword;
        while (getline(ss, keyword, ','))
        {
            memo.erase(keyword);
        }
        oss << memo.size() << '\n';
    }
    cout << oss.str();
    return 0;
}

while문에서 getline을 사용한 것을 보면 


만약 std::cin 입력과 같이 사용한다면 주의가 필요하다.

cin 표준입력은 입력을 받은 뒤에 개행문자가 버퍼에 남아있기 때문에 해당 개행 문자로 인해 getline이 씹힐 수 있다.

 

따라서 동시에 사용하는 경우에는 cin.ignore()를 통해 버퍼를 비워주고 다시 입력을 받는 것이 필요하다.