我正在学习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 2
,1 xy 2
和3 A 8000 E 1777 E 2001
并将其存储在数组或某种STL容器中,以后能够对此信息执行某些操作(比如根据该数字前面是否有“A”,“S”或“M”来加,减或乘数。)
我的程序必须能够识别z和xy是变量,并且z = 2且xy = 2.
答案 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::stol
与long long
或std::stoll
与default 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
}