tag map file parser in C++ by using dkutil

Powered by dKingyo VB2005 | ポケットリファレンス | 図解 辞典 | AJAX | TurboGears

と言う事で、dkutilを使って簡易パーサー書きました。
ちなみにこの日記を書いている時点でdkutilはリリースされていませんのであしからず。
ロジックを見て各自、移植してください。

#include <helper/boost_assert.hpp>
#include <dkutil/dktl/map_ex.hpp>
#include <dkutil/filesystem/std_filestream.hpp>
#include <dkutil/detail/convert_interface.hpp>
#include <dkutil/filesystem/path_string.hpp>


namespace dkutil{


inline std::string file_to_string(path_string_ref filename)
{
 std_filestream x;
 std::string::value_type v[1024]; 
 size_t rs;
 std::string str;

 if(false==x.reset(filename,read_mode | text_mode) ||
  false==x.open())
 {
  throw convert_error("file_to_string error");
 }
 
 for(;x.eof()==false;)
 {//buffer overflow対策は万全
  v[1024 - 1] = '\0';
  rs = x.read(v,1024 - 1);
  dkcmNOT_ASSERT(rs > 1024 - 1);
  v[rs] = '\0';
  str += v;
 }
 return str;
}


struct tag_map_file : public map_ex<std::string,std::string>{
 typedef map_ex<std::string,std::string> base_type;
 typedef base_type::iterator iterator;
 typedef base_type::const_iterator const_iterator;
 typedef base_type::value_type value_type;
 typedef base_type::DATA_TYPE DATA_TYPE;

 bool parse(const char *str,size_t size,const char *tag="</>")
 {
  size_t i,state = 0;
  DATA_TYPE v;
  for(i=0;i<size;i++){
   switch(state){
   case 0:
    v.first.clear();
    v.second.clear();
    //*<name>
    if(tag[0] == str[i]){
     state = 1;
    }
    break;
   case 1:
    //<*name>
    if(tag[2] == str[i]){
     state = 2;
     break;
    }
    v.first += str[i];
    break;
   case 2://<name>*</name>
    if(tag[0] == str[i] && tag[1] == str[i+1])
    {//NULL文字あるからAccess Violationにはならない
     size_t j,len = v.first.size();
     if(size - i > len){
      //後ろのタグを抜き出す
      std::string vl;
      for(j=0;j<len;j++){
       vl += str[i+j+2];
      }
      if(vl != v.first){
       v.second += str[i];
       break;//別の終了タグだった。
      }
     }
     state = 3;
     i++;// "</" を抜かす
     break;
    }
    v.second += str[i];
    break;
   case 3://</*name>
    if(tag[2] == str[i]){
     state = 0;
     if(false==base_type::rb_insert(v)){
      return false;
     }
    }
    break;
   default:
    throw -1;
   }//eos
   
  }//eof
  return true;
 }



};

}//end of namespace

using namespace dkutil;

#include <iostream>
using namespace std;

int main(int argc,const char **argv)
{
 tag_map_file tsf;
 if(argc <= 1) return -1;
 std::string str = file_to_string(argv[1]);

 tsf.parse(str.c_str(),str.size());

 tag_map_file::iterator it = tsf.begin();
 for(;it != tsf.end();it++)
 {
  std::string tx = (*it).first.c_str();
  cout <<"key : " << tx << endl;
  cout <<"contents : " <<endl;
  tx = (*it).second.c_str();
  cout << tx << endl;
  cout <<"---------------------------------" << endl;
 }
 
 return 0;
}

追記:ChangeLog

  • 20070323:データ部にHTMLタグが記述されているとタグ終了の部分が削除されるバグをFIX