我有一个文件,其数据如下:
0, 2, 10
10, 8, 10
10, 10, 10
10, 16, 10
15, 10, 16
17, 10, 16
我希望能够输入文件并将其拆分为三个数组,在此过程中修剪所有多余的空格并将每个元素转换为整数。
由于某些原因,我无法在c ++中找到一种简单的方法。我唯一的成功就是将每一行输入到一个数组中,然后重新修整所有空格然后将其拆分。整个过程花了我20到30行代码,修改另一个分隔符(例如空格)等很难。
这是我在C ++中想要拥有的python:
f = open('input_hard.dat')
lines = f.readlines()
f.close()
#declarations
inint, inbase, outbase = [], [], []
#input parsing
for line in lines:
bits = string.split(line, ',')
inint.append(int(bits[0].strip()))
inbase.append(int(bits[1].strip()))
outbase.append(int(bits[2].strip()))
在python中执行此操作的简便性是我首先转移到它的原因之一。但是,我现在需要在C ++中执行此操作,我不想使用我丑陋的20-30行代码。
任何帮助将不胜感激,谢谢!
答案 0 :(得分:6)
在这个例子中没有真正需要使用boost,因为流可以很好地完成这个任务:
int main(int argc, char* argv[])
{
ifstream file(argv[1]);
const unsigned maxIgnore = 10;
const int delim = ',';
int x,y,z;
vector<int> vecx, vecy, vecz;
while (file)
{
file >> x;
file.ignore(maxIgnore, delim);
file >> y;
file.ignore(maxIgnore, delim);
file >> z;
vecx.push_back(x);
vecy.push_back(y);
vecz.push_back(z);
}
}
虽然如果我要使用提升,我更喜欢tokenizer的简单性来正则表达式... :)
答案 1 :(得分:4)
fscanf确实没有问题,这可能是这种情况下最快的解决方案。它和python代码一样简短易读:
FILE *fp = fopen("file.dat", "r");
int x, y, z;
std::vector<int> vx, vy, vz;
while (fscanf(fp, "%d, %d, %d", &x, &y, &z) == 3) {
vx.push_back(x);
vy.push_back(y);
vz.push_back(z);
}
fclose(fp);
答案 2 :(得分:2)
类似的东西:
vector<int> inint;
vector<int> inbase;
vector<int> outbase;
while (fgets(buf, fh)) {
char *tok = strtok(buf, ", ");
inint.push_back(atoi(tok));
tok = strtok(NULL, ", ");
inbase.push_back(atoi(tok));
tok = strtok(NULL, ", ");
outbase.push_back(atoi(tok));
}
除了错误检查。
答案 3 :(得分:1)
std :: getline允许您读取一行文本,并且您可以使用字符串流来解析单个行:
string buf;
getline(cin, buf);
stringstream par(buf);
char buf2[512];
par.getline(buf2, 512, ','); /* Reads until the first token. */
一旦你将文本行放入字符串中,你就可以使用你想要的任何解析函数,甚至是sscanf(buf.c_str(),“%d,%d'%d”,&amp; i1,&amp; i2,&amp; i3),通过在子串上使用atoi和整数,或者通过其他方法。
如果你知道它们在那里,你也可以忽略输入流中不需要的字符:
if (cin.peek() == ',')
cin.ignore(1, ',');
cin >> nextInt;
答案 4 :(得分:1)
如果您不介意使用Boost库...
#include <string>
#include <vector>
#include <boost/lexical_cast.hpp>
#include <boost/regex.hpp>
std::vector<int> ParseFile(std::istream& in) {
const boost::regex cItemPattern(" *([0-9]+),?");
std::vector<int> return_value;
std::string line;
while (std::getline(in, line)) {
string::const_iterator b=line.begin(), e=line.end();
boost::smatch match;
while (b!=e && boost::regex_search(b, e, match, cItemPattern)) {
return_value.push_back(boost::lexical_cast<int>(match[1].str()));
b=match[0].second;
};
};
return return_value;
}
从流中拉取线条,然后使用Boost :: RegEx库(带有捕获组)从线条中提取每个数字。它会自动忽略任何非有效数字,但如果您愿意,可以更改。
使用#include
s仍然大约有20行,但您可以使用它从文件的行中提取任何。这是一个简单的例子,我使用几乎相同的代码从数据库字段中提取标签和可选值,唯一的主要区别是正则表达式。
const boost::regex cItemPattern(" *([0-9]+), *([0-9]+), *([0-9]+)");
std::vector<int> vector1, vector2, vector3;
std::string line;
while (std::getline(in, line)) {
string::const_iterator b=line.begin(), e=line.end();
boost::smatch match;
while (b!=e && boost::regex_search(b, e, match, cItemPattern)) {
vector1.push_back(boost::lexical_cast<int>(match[1].str()));
vector2.push_back(boost::lexical_cast<int>(match[2].str()));
vector3.push_back(boost::lexical_cast<int>(match[3].str()));
b=match[0].second;
};
};
答案 5 :(得分:1)
为什么不是与python :)相同的代码?
std::ifstream file("input_hard.dat");
std::vector<int> inint, inbase, outbase;
while (file.good()){
int val1, val2, val3;
char delim;
file >> val1 >> delim >> val2 >> delim >> val3;
inint.push_back(val1);
inbase.push_back(val2);
outbase.push_back(val3);
}
答案 6 :(得分:0)
如果你想扩展到更难的输入格式,你应该考虑精神,提升解析器组合库。
This page有一个例子几乎可以满足你的需要(虽然有实数和一个向量)