本问题已经有最佳答案,请猛点这里访问。
这是一个基本的问题,但我在思考解决方案时遇到了麻烦,所以我需要朝着正确的方向努力。
我有一个输入文件,我要把它放入一个字符串变量中。问题是我需要将这个字符串分成不同的东西。将有3个字符串和1个int。它们用":"分隔。
我知道我可以通过find()找到第一个":"的位置,但我真的不知道如何通过字符串进行处理,对于每个事物并将其放入它自己的字符串/ int中。
该文件的实际输入如下所示:
A:PEP:909:Inventory Item
A将成为命令我必须执行...所以这将是一个字符串。
PEP是一个关键,需要是一个字符串。
909是一个int。
最后一个是字符串。
所以我认为我想要做的是拥有3个字符串var和1个int并将所有这些内容放入各自的变量中。
所以我想我最终想要将这个C ++字符串转换为C字符串,所以我可以使用atoi将一个部分转换为int。
多次询问和回答:stackoverflow.com/questions/53849/
那不太一样。 在这种情况下,他需要转换一些东西。 简单的getline循环不会这样做
马丁的链接再次检查。 我在那边发布了我的代码。 它就像一个3行while循环来分割字符串。 然后他可以使用atol(stringVector [2] .c_str())来提取数字。 或atoi()如果他想要的话。 或者环礁()。 或者atoq()。
我经常使用这样的东西:
void split(const std::string &s, char delim, std::vector<:string> &elems) {
std::stringstream ss(s);
std::string item;
while(std::getline(ss, item, delim)) {
elems.push_back(item);
}
}
你可以像这样使用它:
std::vector<:string> tokens;
split("this:is:a:test", ':', tokens);
令牌现在将包含"this","is","a"和"test"
简单,不需要添加另一个库。适合我。
+1我的首选解决方案,没有搞乱find()和索引。
必须喜欢在一年之久的帖子上的downvote,工作得很好......
当您想要使用C ++标准库时,最好使用std::getline和std::istringstream完成此操作:
std::string command;
std::string key;
int id;
std::string item;
std::string line ="A:PEP:909:Inventory Item";
// for each line:
std::istringstream stream(line);
std::getline(stream, command, ':');
std::getline(stream, key, ':');
stream >> id;
std::getline(stream, item);
// now, process them
考虑将它放入自己的结构中:
struct record {
std::string command;
std::string key;
int id;
std::string item;
record(std::string const& line) {
std::istringstream stream(line);
stream >> *this;
}
friend std::istream& operator>>(std::istream& is, record & r){
std::getline(is, r.command, ':');
std::getline(is, r.key, ':');
stream >> r.id;
std::getline(is, r.item);
return is;
}
};
当你击中一个> 3或<3冒号的格式错误的条目时,请注意你不会进入下一行。
是的,它假定线条是正确的。理论上,密钥也可以包含' n',然后它将跨越到下一行。
或者你只是首先提取整行,然后使用记录的ctor。这不会跨越下一行。
只是评论,运营商>>不需要被宣布为朋友。没有私人会员,所以它可以是外部免费功能。
dribeas,它已经是一个免费的功能。但它不能直接调用,只适用于koenig查找(ADT)(参见"朋友名称注入")。我喜欢在这里使用朋友定义,因为它会在您将成员设为私有时进行扩展。
看看boost :: tokenizer。
boost.org/doc/libs/1_37_0/libs/tokenizer/tokenizer.htm
我找到的一个舒适的解决方案并不罕见,是以下原型:
string SplitToken(string & body, char separator)
返回到第一次出现分隔符的所有内容,并删除包含分隔符的那部分。
"我的"MFC - 基于CString的实现如下:
CString SplitStringAt(CString & s, int idx)
{
CString ret;
if (idx < 0)
{
ret = s;
s.Empty();
}
else
{
ret = s.Left(idx);
s = s.Mid(idx+1);
}
return ret;
}
CString SplitToken(CString & s,TCHAR separator)
{
return SplitStringAt(s, s.Find(separator));
}
这绝对不是最有效的方法 - 主要的缺点是修改了主体并为每个令牌创建了一个新的(部分)副本,所以不要在性能关键位置使用它!
但是,对于简单的解析器,我发现这个(以及一些相关的函数)非常有用。
使用C风格的字符串,您可以使用strtok()来执行此操作。你也可以使用sscanf()
但是既然你正在处理C ++,你可能想要坚持使用内置的std :: string函数。因此,您可以使用find()。 Find有一个表单,它接受第二个参数,它是开始搜索的偏移量。所以你可以找到(':')找到第一个实例,然后使用find(':',firstIndex + 1)来查找下一个实例,其中firstIndex是第一次调用find()返回的值。