我需要在开头阅读具有特定关键字的多行。 我有一个基本问题,我需要帮助我。
以下是输入类型:
keyword1 0.0 0.0
keyword1 1.0 5.0
keyword2 10.0
keyword3 0.5
keyword4 6.0
规则是:
包含keyword1&的行keyword2应该按照该顺序和任何其他行之前。
包含keyword3&的行keyword4可以按任何顺序
keyword1后面跟着2个双
keyword2,3& 4必须遵循1双
在包含所有四个关键字后跟其双精度的行块的末尾,“循环”中断并触发计算。
这是我的来源:
using namespace std;
int main (int argc, const char * argv[]) {
vector<double> arrayInputs;
string line;
double keyword1_first, keyword1_second, keyword4,
keyword3, keyword2;
bool inside_keyword1=false, after_keyword2=false,
keyword4_defined=false, keyword3_defined=false ;
//cin.ignore();
while (getline(cin, line)) {
if (inside_keyword1 && after_keyword2 && keyword3 && keyword4) {
break;
}
else
{
std::istringstream split(line);
std::vector<std::string> tokens;
char split_char = ' ';
for (std::string each; std::getline(split, each, split_char); tokens.push_back(each));
if (tokens.size() > 2)
{
if (tokens[0] != "keyword1") return EXIT_FAILURE; // input format error
else
{
keyword1_first = atof(tokens[1].c_str());
keyword1_second = atof(tokens[2].c_str());
inside_keyword1 = true;
}
}
else
{
if (tokens[0] == "keyword2")
{
if (inside_keyword1)
{
keyword2 = atof(tokens[1].c_str());
after_keyword2 = true;
}
else return EXIT_FAILURE; // cannot define anything else keyword2 after keyword1 definition
}
else if (tokens[0] == "keyword3")
{
if (inside_keyword1 && after_keyword2)
{
keyword3 = atof(tokens[1].c_str());
keyword3_defined = true;
}
else return EXIT_FAILURE; // cannot define keyword3 outside a keyword1
}
else if (tokens[0] == "keyword4")
{
if (inside_keyword1 && after_keyword2)
{
keyword4 = atof(tokens[1].c_str());
keyword4_defined = true;
}
else return EXIT_FAILURE; // cannot define keyword4 outside a keyword1
}
}
}
}
// Calculation
// output
return EXIT_SUCCESS;
}
我的问题是:除了在阅读/解析循环中使用布尔值之外,还有更有效的方法吗?
答案 0 :(得分:2)
你问一些“更有效”的东西,但似乎你没有特定的表现目标。所以你想要的更像是Code Review。有一个网站,特别是:
https://codereview.stackexchange.com/
但无论如何......
你是正确的,因为这里并没有真正要求四个布尔人。这是2 ^ 4 = 16种不同的“状态”,其中许多是你永远无法达到的。 (例如,keyword3_defined == true
时,您的规范明确禁止after_keyword1 == false
。
程序状态可以保存在枚举和布尔中。这使得“健忘”循环可以在不同情况下重新访问一行代码,但仍然记住它处理的处理阶段。它在许多情况下都很有用,包括在复杂的解析器中。但是如果你的任务是线性的和简单的,那么最好根据已达到某一行代码来隐式“知道”状态。
作为一个展示我正在谈论的对比的教育例子,这里是一个愚蠢的状态机,用一个字母A
读后跟任意数量的字母B
:
enum State {
beforeReadingAnA,
haveReadAnA,
readingSomeBs,
doneReadingSomeBs
};
State s = beforeReadingAnA;
char c;
while(true) {
switch (s) {
case beforeReadingAnA:
cin >> c;
if (cin.good() && c == 'A') {
// good! accept and state transition to start reading Bs...
s = haveReadAnA;
} else {
// ERROR: expected an A
return EXIT_CODE_FAILURE;
};
break;
case haveReadAnA:
// We've read an A, so state transition into reading Bs
s = readingSomeBs;
break;
case readingSomeBs:
cin >> c;
if (cin.good() && c == 'B') {
// good! stay in the readingSomeBs state
} else if (cin.eof()) {
// reached the end of the input after 0 or more Bs
s = doneReadingSomeBs;
} else {
// ERROR: expected a B or the EOF
return EXIT_CODE_FAILURE;
}
break;
case doneReadingSomeBs:
// all done!
return EXIT_CODE_SUCCESS;
}
}
如前所述,它是一种非常非常有用的编码样式。然而对于这种情况来说这很荒谬。与执行相同操作的简单线性代码进行比较:
// beforeReadingAnA is IMPLICIT
char c;
cin >> c;
if (cin.fail() || c != 'A')
return EXIT_CODE_FAILURE;
// haveReadAnA is IMPLICIT
do {
// readingSomeBs is IMPLICIT
cin >> c;
if (cin.eof())
return EXIT_CODE_SUCCESS;
if (cin.fail() || c != 'B')
return EXIT_CODE_FAILURE;
}
// doneReadingSomeBs is IMPLICIT
所有状态变量都消失了。它们是不必要的,因为程序只是“知道它在哪里”。如果你重新考虑你的例子,那么你可以做同样的事情。你不需要四个布尔值,因为你可以将光标放在一行代码上,并放心地说这四个布尔值必须,如果那行代码恰好在运行。
就效率而言,<iostream>
类可以让生活更轻松,而不是像atof
那样调用C-isms或者不得不使用c_str()
更加惯用C ++ }。让我们看一下代码的简化摘录,它只读取与“keyword1”相关的双精度。
string line;
getline(cin, line);
istringstream split(line);
vector<string> tokens;
char split_char = ' ';
string each;
while (getline(split, each, split_char)) {
tokens.push_back(each);
}
double keyword1_first, keyword1_second;
if (tokens.size() > 2) {
if (tokens[0] != "keyword1") {
return EXIT_FAILURE; // input format error
} else {
keyword1_first = atof(tokens[1].c_str());
keyword1_second = atof(tokens[2].c_str());
}
}
与此对比:
string keyword;
cin >> keyword;
if (keyword != "keyword1") {
return EXIT_FAILURE;
}
double keyword1_first, keyword1_second;
cin >> keyword1_first >> keyword1_second;
万。 Iostream可以检测您尝试读取或写入的类型。如果遇到以您要求的方式解释输入的问题,那么它会将输入留在缓冲区中,以便您可以尝试以另一种方式读取它。 (在要求字符串的情况下,行为是读取一系列字符直到空白......如果你真的想要整行,你可以像使用getline
一样。)
然而,错误处理是您必须处理的事情。有可能告诉iostreams使用异常处理方法,以便遇到问题的标准响应(例如在预期有双重的地方的随机单词)将导致程序崩溃。但默认设置是您需要测试的失败标志:
iostream有细微之处,所以你可能想对问答进行一些调查......我最近在回答/问这里时已经学到了一点: