将一串数据标记为一个结构向量?

将一串数据标记为一个结构向量?

问题描述:

所以我有通过TCP winsock连接接收到的以下字符串数据,并且想要执行高级标记化,将其转换为结构向量,其中每个结构表示一个记录。将一串数据标记为一个结构向量?

std::string buf = "44:william:adama:commander:stuff\n33:luara:roslin:president:data\n" 

struct table_t 
{ 
    std::string key; 
    std::string first; 
    std::string last; 
    std::string rank; 
    std::additional; 
}; 

字符串中的每个记录由一个回车分隔。

void tokenize(std::string& str, std::vector<string>records) 
{ 
    // Skip delimiters at beginning. 
    std::string::size_type lastPos = str.find_first_not_of("\n", 0); 
    // Find first "non-delimiter". 
    std::string::size_type pos  = str.find_first_of("\n", lastPos); 
    while (std::string::npos != pos || std::string::npos != lastPos) 
    { 
     // Found a token, add it to the vector. 
     records.push_back(str.substr(lastPos, pos - lastPos)); 
     // Skip delimiters. Note the "not_of" 
     lastPos = str.find_first_not_of("\n", pos); 
     // Find next "non-delimiter" 
     pos = str.find_first_of("\n", lastPos); 
    } 
} 

似乎完全没有必要再重复了代码通过结肠进一步记号化每个记录(内部字段分隔符)到结构:我分裂了记录,但尚未分手了领域的尝试并将每个结构体推送到一个向量中。我相信有这样做的更好方法,或者设计本身可能是错误的。

谢谢你的帮助。

+1

如果你可以使用提升,这将是相当整齐地做使用它的标记器库,它的字符串算法库,或者对于最强大的解决方案,使用'boost.spirit',如下所示:http://www.boost.org/doc/libs/1_46_1/libs/spirit/doc /html/spirit/qi/tutorials/employee___parsing_into_structs.html – Cubbi 2011-03-28 16:32:03

+0

错过了此评论。对于这种情况下使用的[数据格式太重的012] – user237419 2011-03-28 16:40:10

+0

使用[boost :: tokenizer](http://www.boost.org/doc/libs/1_46_1/libs/tokenizer/index.html) – user237419 2011-03-28 16:38:34

对于将字符串分成记录,我会使用istringstream,如果只有 ,因为这将简化后来当我想从 文件读取更改。对于符号化,最明显的解决方案是刺激::正则表达式,所以:

std::vector<table_t> parse(std::istream& input) 
{ 
    std::vector<table_t> retval; 
    std::string line; 
    while (std::getline(input, line)) { 
     static boost::regex const pattern(
      "\([^:]*\):\([^:]*\):\([^:]*\):\([^:]*\):\([^:]*\)"); 
     boost::smatch matched; 
     if (!regex_match(line, matched, pattern)) { 
      // Error handling... 
     } else { 
      retval.push_back(
       table_t(matched[1], matched[2], matched[3], 
         matched[4], matched[5])); 
     } 
    } 
    return retval; 
} 

(我假设table_t逻辑构造。另外:有一个非常 悠久的传统用C,在_t结尾的名称是类型定义的,所以你 可能会更好过一些寻找其他约定)

+0

你应该ping Siek并告诉他:: tokenizer是无用的,因为使用正则表达式你可以做任何事情。显然 – user237419 2011-03-28 16:46:42

+0

@adirau他问如何避免重复。使用现有工具是显而易见的解决方案。在这种情况下,它也是最简单的解决方案(至少如果你想检查错误)。 – 2011-03-28 17:31:07

+0

避免重复使用代码;不能说如果你使用getline作为第一个标记器和正则表达式作为第二个标记器,你就避免了重复;)不是最简单的,不是明显的,即使你想检查错误也不是;该正则表达式将接受令牌级别的错误;如果他需要错误检查也许:: spirit是一个更好的解决方案,因为Cubbi在第一条评论中提到 – user237419 2011-03-28 17:43:50

我的解决办法:

struct colon_separated_only: std::ctype<char> 
{ 
    colon_separated_only(): std::ctype<char>(get_table()) {} 

    static std::ctype_base::mask const* get_table() 
    { 
     typedef std::ctype<char> cctype; 
     static const cctype::mask *const_rc= cctype::classic_table(); 

     static cctype::mask rc[cctype::table_size]; 
     std::memcpy(rc, const_rc, cctype::table_size * sizeof(cctype::mask)); 

     rc[':'] = std::ctype_base::space; 
     return &rc[0]; 
    } 
}; 

struct table_t 
{ 
    std::string key; 
    std::string first; 
    std::string last; 
    std::string rank; 
    std::string additional; 
}; 

int main() { 
     std::string buf = "44:william:adama:commander:stuff\n33:luara:roslin:president:data\n"; 
     stringstream s(buf); 
     s.imbue(std::locale(std::locale(), new colon_separated_only())); 
     table_t t; 
     std::vector<table_t> data; 
     while (s >> t.key >> t.first >> t.last >> t.rank >> t.additional) 
     { 
      data.push_back(t); 
     } 
     for(size_t i = 0 ; i < data.size() ; ++i) 
     { 
      cout << data[i].key <<" "; 
      cout << data[i].first <<" "<<data[i].last <<" "; 
      cout << data[i].rank <<" "<< data[i].additional << endl; 
     } 
     return 0; 
} 

输出:

44 william adama commander stuff 
33 luara roslin president data 

在线演示:http://ideone.com/JwZuk


我这里使用的技术在我的另一个解决不同的问题描述:

Elegant ways to count the frequency of words in a file

+0

我还没有检查出ctype,将不得不阅读它。感谢您的帮助。 – rem45acp 2011-03-29 12:05:29