将一串数据标记为一个结构向量?
所以我有通过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);
}
}
似乎完全没有必要再重复了代码通过结肠进一步记号化每个记录(内部字段分隔符)到结构:我分裂了记录,但尚未分手了领域的尝试并将每个结构体推送到一个向量中。我相信有这样做的更好方法,或者设计本身可能是错误的。
谢谢你的帮助。
对于将字符串分成记录,我会使用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结尾的名称是类型定义的,所以你 可能会更好过一些寻找其他约定)
你应该ping Siek并告诉他:: tokenizer是无用的,因为使用正则表达式你可以做任何事情。显然 – user237419 2011-03-28 16:46:42
@adirau他问如何避免重复。使用现有工具是显而易见的解决方案。在这种情况下,它也是最简单的解决方案(至少如果你想检查错误)。 – 2011-03-28 17:31:07
避免重复使用代码;不能说如果你使用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
我这里使用的技术在我的另一个解决不同的问题描述:
我还没有检查出ctype,将不得不阅读它。感谢您的帮助。 – rem45acp 2011-03-29 12:05:29
如果你可以使用提升,这将是相当整齐地做使用它的标记器库,它的字符串算法库,或者对于最强大的解决方案,使用'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
错过了此评论。对于这种情况下使用的[数据格式太重的012] – user237419 2011-03-28 16:40:10
使用[boost :: tokenizer](http://www.boost.org/doc/libs/1_46_1/libs/tokenizer/index.html) – user237419 2011-03-28 16:38:34