如何在C ++中读取格式错误的输入数据?

时间:2016-03-07 04:44:33

标签: c++ stl containers

我正在学习C ++而且我正在练习。如何读取格式不正确的数据?例如,我得到一个文件,我需要读取这样的数据:

1   z 2
1   xy 2
3   A 8000  E 1777  E 2001

第一,第二和第三行组成一个“模块”。许多模块都有很多数据可以通过键盘输入。我的程序必须接受所有用户的输入(直到用户决定键入“q”退出),然后读取该输入并操纵数据。理想情况下,输入将像上面的示例一样正确格式化,但有时数据将具有额外的空格,制表符,回车符或从前一个模块的数据开始,如下所示:

2   R 5001  E 4777 1   z 2     1   xy 2
3   A 8000  E 1777
E 2001

使用错误格式化读取和操作输入数据的最佳方法是什么?在这种情况下,我希望能够提取1 z 21 xy 23 A 8000 E 1777 E 2001并将其存储在数组或某种STL容器中,以后能够对此信息执行某些操作(比如根据该数字前面是否有“A”,“S”或“M”来加,减或乘数。)

我的程序必须能够识别z和xy是变量,并且z = 2且xy = 2.

4 个答案:

答案 0 :(得分:2)

如果您更好地描述输入部分的逻辑目的,您会得到更好的答案。我将猜测每个模块都会开始计算将跟随多少个变量名/数值对,从而允许更加结构化的方法来读取和存储值。我填充了从变量名到值的映射(二叉树)的向量(数组),这可能方便以后的查找和处理。

std::vector<std::map<std::string, int>>> vars;
int vars_in_module;
while (cin >> vars_in_module)
{
    vars.emplace_back();  // add an empty module to vector
    std::string identifier;
    int value;
    for (int i = 1; i <= vars_in_module; ++i)
        if (cin >> identifier >> value)
            vars.back()[identifier] = value;  // add var to module
        else
        {
            std::cerr << "error parsing variable identifier & value\n";
            exit(1);
        }
}

map按字典顺序重新排序(使用最左边字符的ASCII顺序,然后 - 如果相等 - 右边的那个等),而不是保留它们的输入顺序,根据您放置变量的用途,这可能或不重要。 map以后可以快速搜索特定标识符,但如果您关心输入顺序,则可以使用vector

答案 1 :(得分:1)

您可以使用std::cin >>来避免空白

std::string input = "";
std::vector<std::vector<std::string>> data;
std::vector<std::string> temp;
unsigned line = 1;

while (std::cin >> input && input != "q") {
    temp.push_back(input);
    if (int(input) == line && line != 1) {
        data.push_back(temp);
        temp.clear();
        line++;
    }
}

这将填充data向量,其中标准输入的所有输入都不是空格,直到输入“q”。

那是你在找什么?

编辑:我逐行(按行号)解析请求。

答案 2 :(得分:1)

您可以使用正则表达式:

#include <regex>
#include <string>
#include <iostream>

int main()
{
    // get data from file or user input etc. Here I have hardcoded it with
    // some newlines just to show how it works.
    std::string data =
        R"(2   R 5001  E 4777 1   z 2     1
        xy 2        3   A 8000
        E 1777        E 2001)";

    // Unfortunately the amount of space involved makes this regex rather
    // ugly, but basically "\s+" means to match at least one whitespace
    // character (which includes newlines, tabs, and spaces)
    std::regex moduleregex(R"(1\s+z\s+2\s+1\s+xy\s+2\s+3\s+([AMS])\s+(\d+)\s+E\s+(\d+)\s+E\s+(\d+))");

    std::smatch result;
    if (std::regex_search(data, result, moduleregex))
    {
        // Program will end up here if the match was successful
        std::string op = result[1];
        int operand1 = std::stoi(result[2]);
        int operand2 = std::stoi(result[3]);
        int operand3 = std::stoi(result[4]);

        // based on the input above:
        // "op" now contains "A" (it could be "M" or "S" depending on input)
        // "operand1" now contains 8000
        // "operand2" now contains 1777
        // "operand3" now contains 2001
    }
    else
    {
        std::cerr << "Could not find module information in input" << std::endl;
    }
}

请注意,除了输入是否与正则表达式匹配外,此处没有错误检查。您需要将代码包装在try / catch块中并捕获std::out_of_range,如果输入对于int类型来说太大,则会抛出long(您也可以如果您需要支持更高的范围,请将std::stollong longstd::stolldefault value一起使用。它也只会匹配正数。如果你想匹配负数,那就留给读者练习了!

答案 3 :(得分:0)

这种事情很难做到。这是我的:

ifstream in("file.txt");
vector<string> v;
string line;

while(getline(in, line)) {
    v.push_back(line.substr(1));   // remove line number
}