2

所以我有以下数据字符串,它是通过 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);
    }
}

似乎完全没有必要再次重复所有代码以通过冒号(内部字段分隔符)将每个记录进一步标记到结构中并将每个结构推入向量中。我确信有更好的方法可以做到这一点,或者设计本身可能是错误的。

感谢您的任何帮助。

4

2 回答 2

2

我的解决方案:

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


我在这里使用的技术在我对不同问题的另一个解决方案中进行了描述:

计算文件中单词频率的优雅方法

于 2011-03-28T17:45:27.063 回答
1

为了将字符串分解为记录,我会使用 istringstream,如果只是因为这会简化稍后我想从文件中读取的更改。对于标记化,最明显的解决方案是 boost::regex,所以:

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 结尾的名称是 typedef 的,所以你最好找到一些其他的约定。)

于 2011-03-28T16:41:16.633 回答