'boost'에 해당되는 글 4건

  1. 2008/06/18 귀차니스트 strtok 는 이제 그만..
  2. 2008/04/03 귀차니스트 Boost 1.35 - 워크샵 뒤의 포스팅 (2)
  3. 2008/03/12 귀차니스트 더 이상 rand()는 필요없다?! - boost::random Number Library (2)
  4. 2008/03/12 귀차니스트 TR1 Array - boost 라이브러로 사용하는 방법 (1)

strtok 는 이제 그만..

Programming 2008/06/18 11:58 귀차니스트

  이틀 의 공백기간 후 올리는 포스팅 이군요. 퇴근시간이 약간 늦어지는 것 때문에 막상 도착하니 짧은 시간에 무엇을 할까 고심을 많이 했습니다. 최근 계속해서 알고리즘 트레이닝 북에 있는 문제를 하나씩 풀어가고 있긴 했지만 워낙 남은 시간이 짧아 조금 그렇더군요.

  그래서 오늘 마침 빨리 퇴근한 김에 수정하고 있는 프로그램에서 쓰고 있는 boost::tokenizer 를 보기로 했습니다. 아주 예전 C 부터 사용하던 분들이라면 strtok 함수를 이용하여 토큰을 분리하거나, 직접 코드를 작성하여 코드를 분리하곤 했습니다. 파싱을 통한 토큰 분리를 수행해 주는 여타 클래스도 존재하긴 합니다.
  그런 김에 boost::tokenizer를 보니 stl과 비슷한 방법으로 토큰 분리를 해주는 클래스를 보니 무척 반갑더군요. 그런데 문제는 하나 있었습니다. 일단 코드를 한 번 보도록 하겠습니다.

Tokenizer.cpp (Language : cpp)
  1. #include <iostream>
  2. #include <boost/tokenizer.hpp>
  3. int main( int argc, char **argv )
  4. {
  5.     std::string aa = "a bb ccc ddd";
  6.     boost::tokenizer<> Token(aa);
  7.     for(boost::tokenizer<>::iterator Iter=Token.begin(); Iter!=Token.end();++Iter)
  8.         std::cout << *Iter << "\n";
  9.     return 0;
  10. }

  위 코드 수행시 결과는 a\nbb\rccc\nddd 입니다. \n는 뉴라인이라고 생각하시면 결과를 추측하실 수 있겠죠? 간단하게 출력을 수행하는 부분인데, 기본적인 이 방법으로는 std::string 형인 aa에 한글이 섞여있는 문자열을 적을경우 분리가 불가능하며 심지어 에러를 표시합니다.
  그래서 선언을 봤는데 token_functions.hpp에 있는 seperator를 기본으로 사용하듯이 한글이나 2바이트 확장 아스키에 대해서는 추가로 seperator 클래스를 구현해주어야 하더군요.

sjis_seperator.cpp (Language : cpp)
  1. class escaped_list_separator_sjis
  2. {
  3.   private:
  4.     bool last_;
  5.     enum {
  6.         QUOTE     = '\"'// 囲み記号
  7.         SEPARATOR = ',',        // 区切り記号
  8.         ESCAPE    = '\\',       // エスケープ記号
  9.     };
  10.     // マルチバイトコードの1byte目判定
  11.     bool is_multibyte1(char c_)
  12.     {
  13.         unsigned char c = static_cast<unsigned char>(c_);
  14.         return ((c >= 0x81 && c <= 0x9f) || (c >= 0xe0 && c <= 0xfc));
  15.     }
  16.     // マルチバイトコードの2byte目判定
  17.     bool is_multibyte2(char c_)
  18.     {
  19.         unsigned char c = static_cast<unsigned char>(c_);
  20.         return ((c >= 0x40 && c <= 0x7e) || (c >= 0x80 && c <= 0xfc));
  21.     }
  22.     // エスケープ文字の処理
  23.     template <typename iterator, typename Token>
  24.     void do_escape(iterator& next, iterator end, Token& tok)
  25.     {
  26.         if (++next == end)
  27.             throw boost::escaped_list_error(std::string("cannot end with escape"));
  28.         switch (*next) {
  29.           case 'n':
  30.             tok += '\n';
  31.             break;
  32.           case QUOTE:
  33.           case SEPARATOR:
  34.           case ESCAPE:
  35.             tok += *next;
  36.             break;
  37.           default:
  38.             throw boost::escaped_list_error(std::string("unknown escape sequence"));
  39.         }
  40.     }
  41.     // マルチバイト文字の処理
  42.     template <typename iterator, typename Token>
  43.     void do_multibyte(iterator& next, iterator end, Token& tok)
  44.     {
  45.         tok += *next;
  46.         if (++next == end)
  47.             throw boost::escaped_list_error(std::string("cannot end with multi byte"));
  48.         if (is_multibyte2(*next)) {
  49.             tok += *next;
  50.         } else {
  51.             throw boost::escaped_list_error(std::string("unknown multi byte code"));
  52.         }
  53.     }
  54.   public:
  55.     escaped_list_separator_sjis(void) : last_(false)
  56.     {
  57.     }
  58.     void reset() {last_=false;}
  59.     template <typename InputIterator, typename Token>
  60.     bool operator()(InputIterator& next, InputIterator end, Token& tok)
  61.     {
  62.         bool bInQuote = false;
  63.         tok = Token();
  64.         if (next == end) {
  65.             if (last_) {
  66.                 last_ = false;
  67.                 return true;
  68.             } else {
  69.                 return false;
  70.             }
  71.         }
  72.         last_ = false;
  73.         for ( ; next != end; ++next) {
  74.             switch (*next) {
  75.               case ESCAPE:
  76.                 do_escape(next, end, tok);
  77.                 break;
  78.               case SEPARATOR:
  79.                 if (!bInQuote) {
  80.                     ++next;
  81.                     last_ = true;
  82.                     return true;
  83.                 } else {
  84.                     tok+=*next;
  85.                 }
  86.                 break;
  87.               case QUOTE:
  88.                 bInQuote=!bInQuote;
  89.                 break;
  90.               default:
  91.                 if (is_multibyte1(*next)) {
  92.                     do_multibyte(next, end, tok);
  93.                 } else {
  94.                     tok += *next;
  95.                 }
  96.                 break;
  97.             }
  98.                }
  99.         return true;
  100.     }
  101. };

Token.cpp (Language : cpp)
  1. vector<string> fromCSV2_3(const string& csv)
  2. {
  3.     vector<string> data;
  4.     boost::tokenizer<escaped_list_separator_sjis> tok(csv);
  5.     copy(tok.begin(), tok.end(), back_inserter(data));
  6.     return data;
  7. }

  위와 같은 클래스를 구현해주고, 해당 tokenizer에서 사용하는 TokenizerFunc Template 인자에 넣어주면 됩니다. 어차피 Template 이라는 자체가 결과적으로는 Define 치환결과하고 동일하다고 볼 수 있으니까요. 예전 strtok혹은 개별 토큰 기능을 구현하기 보다는 이런 클래스를 사용한다면 에러가 더 적게 발생하지 않을까요? 당연한 말이겠지만 이미 이런 클래스들은 여러사람이 사용하고 문제점은 이미 검증되었으니까요.
  만약 이런 클래스 구현을 통한 확장 아스키 지원이 조금 걸리면 Unicode 변환 -> Tokenizing -> 확장아스키 변환 이런 방법도 있겠네요. 사실 최근 대세가 Unicode로 돌아선지 꽤 되었다 보니, 이미 Unicode 형태로 처리를 하고 있을지도 모르겠습니다. 그래도 예전에 사용했거나 필요할 때 이 글을 보면서 구현을 하면 될 듯 하군요. 그럼 오늘도 즐거운 하루 되세요..^^

크리에이티브 커먼즈 라이센스
Creative Commons License
2008/06/18 11:58 2008/06/18 11:58

댓글을 달아 주세요

Boost 1.35 - 워크샵 뒤의 포스팅

Small Talk 2008/04/03 23:41 귀차니스트

  정신이 약간 오락가락 하네요. 너무 놀아서 그런가 봅니다. 오늘 12시쯤 회사로 출근을 하여 웹 서핑중 boost 의 1.35 버젼 릴리즈 소식이 보이더군요. 개인적으로 엄청 좋아하는 라이브러리이다 보니 반갑기 그지 없었습니다. 자자 어떤게 업데이트 되었냐구요??

 새로 추가된 라이브러리 

  • ASIO - 소켓과 소켓 iostream 지원과, Portable Networking
  • Bimap - Bidirectional Map 라이브러리( Associative Container 의 하나 )
  • Circula Buffer - ring 혹은 Cyclic 버퍼로 알려진 STL Container
  • Function - 함수 포인터, 함수 레퍼런스 등..
  • Fusion - tuple에 적용되어 작용하는 라이브러리, tr1에서 tuple이 정식으로 승격되었죠?
  • GIL - 일반적인 이미지 라이브러리
  • Interprocess - Shared Memory, Memory Mapped File, Process-Shared Mutex.. 등등 이게 가장 눈에 띄네요?^^
  • Intrusive, Math/ Special Function 등 여러가지가 추가되었습니다.

  • 업데이트 된 라이브러리

  • Graph
  • Hash
  • Iostreams
  • multiarray
  • Multi-Index Containers
  • Serialization
  • Thread
  • Wave
  • Xpressive

  •   대충 살펴보니 좋은게 많이 추가된 것 같습니다. 에구 있는 것도 다 파악 못했는데, 아주 주르르륵 쏟아져 나오는군요. 조금씩 살펴보면서 적재적소에 사용을 해봐야겠습니다. 회사에서 건네받은 다른회사가 진행하고 제가 유지보수 해야 될 프로젝트 부분을 보니 std::lexical_???? 쪽 함수를 사용하더군요.
      마음이 설레어 옵니다^^;

    크리에이티브 커먼즈 라이센스
    Creative Commons License
    2008/04/03 23:41 2008/04/03 23:41
    TAG , ,

    댓글을 달아 주세요

    1. kkamagui 2008/04/21 09:29  댓글주소  수정/삭제  댓글쓰기

      와우~ 이미지쪽 라이브러리도 들어있네...
      Boost Library는 참 대단한 것 같다... @0@
      만물상 같은 느낌이랄까... ㅎㅎ

    TraditionalRandom.c (Language : cpp)
    1. #include <stdio.h>
    2. #include <time.h>
    3. #include <stdlib.h>
    4. int main( int argc, char **argv )
    5. {
    6.     srand(time(NULL) );
    7.     for( int i = 0; i < 50; ++i )   {
    8.         printf( "%d\n", rand() % 6 + 1 );
    9.     }
    10.     return 0;
    11. }

      위 구문이 익숙하시죠?? 보통 C/C++을 하시다가 어떠한 난수를 발생시키고자 할 때에 한 번쯤은 써보셨을 겁니다. 그런데 실질적으로 srand 라는 부분도 문제가 되고, % 연산자로 숫자의 범위를 만들어 주어야 하는 단점이 존재합니다. 그 뿐만 아니라 rand() 함수 자체가 short 형인 65536 까지 제한이 걸리다 보니 하고 싶은 작업에 있어서도 제한이 걸립니다. 그런데 역시라고 해야 될지 boost 에는 이런 문제를 해결 해놓은 라이브러리가 존재합니다. 바로 boost::random 입니다.

    random.cpp (Language : cpp)
    1. #include <iostream>
    2. #include <boost/tr1/random.hpp>
    3. int main( int argc, char **argv )
    4. {
    5.     //boost::minstd_rand    Random1;
    6.     //boost::minstd_rand0   Random2;
    7.     //boost::mt11213b      Random3;
    8.     boost::mt19937    Random4;
    9.     boost::uniform_int<>    Six( 1, 6 );
    10.     boost::variate_generator< boost::mt19937, boost::uniform_int<> > Dice( Random4, Six );
    11.     for( int i = 0; i < 50; ++i )
    12.         std::cout << Dice() << std::endl;
    13.     return 0;
    14. }

      간단하게 보이죠?? mt19937 같은 부분은 난수발생엔진 부분이고 uniform_int 는 범위와 데이터 형태를 정의하는 부분입니다. varitate_generator 를 이용하여 해당 엔진을 typename 으로 하여 Dice 롤링을 하죠. 그 것을 바로 std::cout 을 이용해 출력하면 콘솔에서 제대로 출력됩니다. 1 ~ 6 의 숫자가 50번 동안 난발적으로 생성됩니다. 뿐만 아니라 boost::uniform_int 대신 boost::uniform_real를 사용하면 실수가 나옵니다. @0@ 많이 편하지 않나요^^. 사용할 곳이 많이 생길지도 모르겠네요.

    크리에이티브 커먼즈 라이센스
    Creative Commons License
    2008/03/12 22:18 2008/03/12 22:18

    댓글을 달아 주세요

    1. 나쁜남자 2010/08/19 16:01  댓글주소  수정/삭제  댓글쓰기

      많은 도움이 됐습니다.

      흔히 말하는 프로그래밍의 기본이라는 C/C++을 하지 않아도 어떠한 언어를 하다보면 배열이라는 것을 배우게 됩니다. 그런데 아시다시피 C/C++ 에서 기본 배열을 사용하게 되면 길이를 비롯해서 불편함 점이 많습니다. 그래서 보통 사람들은 std::vector 를 사용하는 경향이 있는데요.
      boost 에 올라와있다 TR1 표준에 포함되는 것 중에는 Array 클래스가 존재합니다. 뭐 굳이 얘길 한다면 뭐라 말할 정도로 편리해 지지는 않았지만 해당 부분에 있어서 기타 STL 알고리즘과 호환되게 하는 면이 중점적으로 다루어진것 같았습니다.

    Array.cpp (Language : cpp)
    1. #include <iostream>
    2. #include <boost/tr1/array.hpp>
    3. int main( int argc, char **argv )
    4. {
    5.     boost::array<int,4> a = { 1, 2, 3 };
    6.     std::copy( a.begin(), a.end(), std::ostream_iterator< int >( std::cout, "\r\n" ) );
    7.     return 0;
    8. }

      사용법은 다음과 같습니다. 헤더는 위의 boost 라이브러리가 프로젝트 인클루드 폴더에 포함되어있다는 가정하에 컴파일이 가능하며, 이 것이 begin, end 같은 부분으로 많이 편리해졌다는 것을 알 수 있습니다. 선언에서는 데이터 형태와, 크기를 넣어주어야 하죠. 물론 실질적으로 그냥 사용할 때는 [] 리터럴을 사용하는 배열과 별 다른점을 느끼지 못할지도 모르겠지만 STL 상에서 traits 들과 결합하여 사용한다면 사용법에 있어서 많은 편리함이 생길것 같습니다.

    크리에이티브 커먼즈 라이센스
    Creative Commons License
    2008/03/12 21:53 2008/03/12 21:53

    댓글을 달아 주세요

    1. 구리구리 2009/02/23 14:47  댓글주소  수정/삭제  댓글쓰기

      잘 정리해놓으셨네요 글 좀 퍼가겠습니다.