8

我有一个文件,其中列出的数据如下:

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 行代码。

任何帮助将不胜感激,谢谢!

4

7 回答 7

7

在这个例子中没有真正需要使用 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);
    }
}

虽然如果我要使用 boost 我更喜欢tokenizer的简单性而不是正则表达式...... :)

于 2008-11-06T05:30:44.190 回答
5

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);
于 2008-11-06T08:26:16.940 回答
3

就像是:

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));
}

除了错误检查。

于 2008-11-06T02:03:55.777 回答
2

为什么与 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);
}
于 2008-11-06T09:02:50.640 回答
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", &i1, &i2, &i3),通过使用atoi 使用整数或通过其他方法在子字符串上。

如果您知道它们在那里,您还可以忽略输入流中不需要的字符:

if (cin.peek() == ',')
    cin.ignore(1, ',');
cin >> nextInt;  
于 2008-11-06T02:39:53.660 回答
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 库(带有捕获组)从行中提取每个数字。它会自动忽略任何不是有效数字的内容,但如果您愿意,可以对其进行更改。

s 仍然有大约 20 行,但您可以使用它从文件的行#include中提取任何内容。这是一个简单的例子,我使用几乎相同的代码从数据库字段中提取标签和可选值,唯一的主要区别是正则表达式。

编辑:哎呀,你想要三个独立的向量。试试这个轻微的修改:

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;
    };
};
于 2008-11-06T03:31:18.953 回答
0

如果您希望能够扩展到更难的输入格式,您应该考虑精神,提升解析器组合器库。

这个页面有一个例子,它几乎可以满足你的需要(虽然有实数和一个向量)

于 2008-11-06T09:29:12.913 回答