Turbo-C
C++Builder  |  Delphi  |  FireMonkey  |  C/C++  |  Free Pascal  |  Firebird
볼랜드포럼 BorlandForum
 경고! 게시물 작성자의 사전 허락없는 메일주소 추출행위 절대 금지
터보-C 포럼
Q & A
FAQ
팁&트릭
강좌/문서
자료실
Lua 게시판
볼랜드포럼 홈
헤드라인 뉴스
IT 뉴스
공지사항
자유게시판
해피 브레이크
공동 프로젝트
구인/구직
회원 장터
건의사항
운영진 게시판
회원 메뉴
북마크
볼랜드포럼 광고 모집

C/C++ 팁&트릭
[9] [STL]find_last_of, find_first_not_of, find_last_not_of 알고리듬의 구현
김백일 [cedar] 7256 읽음    2002-05-21 03:55
안녕하세요? cedar 김백일입니다.
간만에 STL 팁을 또 올려봅니다.

제일 처음에 올렸던 글(string에서의 trim() 구현)에서 설명한 바와 같이
string(basic_string)에는 find_first_of(), find_last_of(), find_first_not_of(), find_last_not_of()와 같은 멤버 함수들이 있어서,
trim()이나 토크나이저(tokenizer)와 같은 기능들을 손쉽게 구현할 수 있습니다.

반면에 string 뿐만 아니라 모든 시퀀스 컨테이너에 적용가능한
일반(generic) 알고리듬에는 find_first_of 밖에는 없습니다.

template <class InputIterator, class ForwardIterator>
InputIterator find_first_of(InputIterator first1, InputIterator last1,
                            ForwardIterator first2, ForwardIterator last2);

template <class InputIterator, class ForwardIterator, class BinaryPredicate>
InputIterator find_first_of(InputIterator first1, InputIterator last1,
                            ForwardIterator first2, ForwardIterator last2,
                            BinaryPredicate comp);

(이 알고리듬의 의미를 다시 한번 설명하면,
매개 변수로서 "검색 범위"와 "포함 집합"를 지정해주면 그 포함 집합의 원소에 해당하는
요소가 나타나는 가장 첫 위치를 검색 범위에서 찾아준다는 의미입니다.)
반면에 "해당되지 않는" 요소가 나타나는 가장 첫 위치를 찾는 알고리듬(find_first_not_of)
는 애석하게도 없습니다.

보통 이런 기능은 문자열에 대해서 많이 쓰기 마련인데요,
문자열이 반드시 string이어야 하는 것은 아닙니다.
경우에 따라 기존 C API이나 VCL의 AnsiString과의 호환을 위해
'구닥다리'인 char 배열이나 vector<char> (char 배열과 메모리 구조가 동일합니다.)를
써야할 경우도 있기 마련입니다.

이런 경우를 위해서,
find_last_of, find_first_not_of, find_last_not_of 알고리듬을 구현해 보았습니다.
(빌더 6 STLport의 find_first_of의 소스 코드를 바탕으로 수정했습니다.)

//-----------------------------------------------------------------------------

template <typename BidirectionalIterator1, typename BidirectionalIterator2>
BidirectionalIterator1 find_last_of(BidirectionalIterator1 first1,
                          BidirectionalIterator1 last1,
                          BidirectionalIterator2 first2,
                                       BidirectionalIterator2 last2)
{
    do {
        --last1;
        for (BidirectionalIterator1 iter = first2; iter != last2; ++iter)
              if (*last1 == *iter)
                return last1;
    } while (first1 != last1);
    return first1;
}

template <typename BidirectionalIterator1, typename BidirectionalIterator2,
          typename BinaryPredicate>
BidirectionalIterator1 find_last_of(BidirectionalIterator1 first1,
                     BidirectionalIterator1 last1,
                                       BidirectionalIterator2 first2,
                                       BidirectionalIterator2 last2,
                                       BinaryPredicate pred)
{
    do {
        --last1;
        for (BidirectionalIterator1 iter = first2; iter !=last2; ++iter)
              if (pred(*last1, *iter))
                return last1;
    } while (first1 != last1);
    return first1;
}


template <typename ForwardIterator1, typename ForwardIterator2>
ForwardIterator1 find_first_not_of(ForwardIterator1 first1,
                         ForwardIterator1 last1,
                         ForwardIterator2 first2,
                                      ForwardIterator2 last2)
{
    while (first1 != last1 && find(first2, last2, *first1) != last2)
          ++first1;
    return first1;
}

template <typename ForwardIterator1, typename ForwardIterator2,
          typename BinaryPredicate>
ForwardIterator1 find_first_not_of(ForwardIterator1 first1,
                                   ForwardIterator1 last1,
                                   ForwardIterator2 first2,
                                   ForwardIterator2 last2,
                                   BinaryPredicate pred)
{
    while (first1 != last1 &&
        find_if(first2, last2, bind1st(pred, *first1)) != last2)
          ++first1;
    return first1;
}


template <typename BidirectionalIterator1, typename BidirectionalIterator2>
BidirectionalIterator1 find_last_not_of(BidirectionalIterator1 first1,
                              BidirectionalIterator1 last1,
                              BidirectionalIterator2 first2,
                                           BidirectionalIterator2 last2)
{
    do
          --last1;
    while (first1 != last1 && find(first2, last2, *last1) != last2);
    return last1;
}


template <typename BidirectionalIterator1, typename BidirectionalIterator2,
          typename BinaryPredicate>
BidirectionalIterator1 find_last_not_of(BidirectionalIterator1 first1,
                                   BidirectionalIterator1 last1,
                                          BidirectionalIterator2 first2,
                                          BidirectionalIterator2 last2,
                                          BinaryPredicate pred)
{
    do
          --last1;
    while (first1 != last1 &&
        find_if(first2, last2, bind1st(pred, *last1)) != last2);
    return last1;
}

//-----------------------------------------------------------------------------


다음은 이들 알고리듬을 사용하는 예제 소스코드입니다.
char 배열과 vector<char>에 적용한 예제입니다.
특히 '구닥다리' C 배열과 STL의 알고리듬을 어떻게 조합하는가를 잘보시기 바랍니다.
STL의 반복자(iterator)는 포인터와 같다는 것을 생각하시면 쉽게 이해하실 수 있습니다.
또한 printf와 ostreambuf_iterator의 사용 방법을 대조해서 보시기 바랍니다.


//---------------------------------------------------------------------------

#include <cstring>
#include <iostream>
#pragma hdrstop
#include <vector>
#include <algorithm>
#include <functional>

//---------------------------------------------------------------------------

#pragma argsused
using namespace std;

template <typename Container>
inline Container make(const char s[])
{
    return Container(&s[0], &s[strlen(s)]);
}

// (생략: 위의 알고리듬의 원형 선언)

int main(int argc, char* argv[])
{
    char *WS = "\t\n ";
    int n_WS = strlen(WS);
    char *sentence = "This sentence contains five words.";
    char *ltrim = "   One Word";
    char *rtrim = "One Word   ";

    printf("First word of sentence: \"%.*s\"\n",
          find_first_of(sentence, sentence + strlen(sentence), WS, WS + n_WS)
              - sentence,
          sentence);
    printf("Last word of sentence: \"%s\"\n",
          find_last_of(sentence, sentence + strlen(sentence), WS, WS + n_WS) + 1);

    printf("Left trim of  \"%s\" : \"%s\"\n", ltrim,
        find_first_not_of(ltrim, ltrim + strlen(ltrim), WS, WS + n_WS));
    printf("Left trim of  \"%s\" : \"%s\"\n", ltrim,
        find_first_not_of(ltrim, ltrim + strlen(ltrim), WS, WS + n_WS,
            equal_to<char>()));
    printf("Right trim of \"%s\" : \"%.*s\"\n", rtrim,
        find_last_not_of(rtrim, rtrim + strlen(rtrim), WS, WS + n_WS)
            - rtrim + 1,
        rtrim);
    printf("Right trim of \"%s\" : \"%.*s\"\n", rtrim,
        find_last_not_of(rtrim, rtrim + strlen(rtrim), WS, WS + n_WS,
            equal_to<char>()) - rtrim + 1,
        rtrim);


    vector<char> v_WS = make< vector<char> >(WS);
    vector<char> v_sentence = make< vector<char> >(sentence);
    vector<char> v_ltrim = make< vector<char> >(ltrim);
    vector<char> v_rtrim = make< vector<char> >(rtrim);

    cout << "\nFirst word of sentence: \"";
    copy(v_sentence.begin(),
        find_first_of(v_sentence.begin(), v_sentence.end(), v_WS.begin(), v_WS.end()),
        ostreambuf_iterator<char>(cout));
    cout << "\"\nLast word of sentence: \"";
    copy(find_last_of(v_sentence.begin(), v_sentence.end(), v_WS.begin(), v_WS.end()) + 1,
        v_sentence.end(), ostreambuf_iterator<char>(cout));
    cout << "\"\nLeft trim of  \"" << ltrim << "\" : \"";
    copy(find_first_not_of(v_ltrim.begin(), v_ltrim.end(), v_WS.begin(), v_WS.end()),
        v_ltrim.end(), ostreambuf_iterator<char>(cout));
    cout << "\"\nLeft trim of  \"" << ltrim << "\" : \"";
    copy(find_first_not_of(v_ltrim.begin(), v_ltrim.end(), v_WS.begin(), v_WS.end(),
        equal_to<char>()), v_ltrim.end(), ostreambuf_iterator<char>(cout));
    cout << "\"\nRight trim of \"" << rtrim << "\" : \"";
    copy(v_rtrim.begin(),
        find_last_not_of(v_rtrim.begin(), v_rtrim.end(), v_WS.begin(), v_WS.end()) + 1,
        ostreambuf_iterator<char>(cout));
    cout << "\"\nRight trim of \"" << rtrim << "\" : \"";
    copy(v_rtrim.begin(),
        find_last_not_of(v_rtrim.begin(), v_rtrim.end(), v_WS.begin(), v_WS.end(),
            equal_to<char>()) + 1, ostreambuf_iterator<char>(cout));
    cout << "\"\n";

    return 0;
}

//---------------------------------------------------------------------------


출력 결과는 다음과 같습니다.


First word of sentence: "This"
Last word of sentence: "words."
Left trim of  "   One Word" : "One Word"
Left trim of  "   One Word" : "One Word"
Right trim of "One Word   " : "One Word"
Right trim of "One Word   " : "One Word"

First word of sentence: "This"
Last word of sentence: "words."
Left trim of  "   One Word" : "One Word"
Left trim of  "   One Word" : "One Word"
Right trim of "One Word   " : "One Word"
Right trim of "One Word   " : "One Word"

+ -

관련 글 리스트
9 [STL]find_last_of, find_first_not_of, find_last_not_of 알고리듬의 구현 김백일 7256 2002/05/21
Google
Copyright © 1999-2015, borlandforum.com. All right reserved.