C++ 多读几行,尤其是。。。有效地解析它们

C++ 多读几行,尤其是。。。有效地解析它们,c++,parsing,split,cin,C++,Parsing,Split,Cin,我需要阅读多行与特定的关键字在开始。 我有一个基本的问题,我需要帮助 以下是输入类型: 关键词1 0.0 0.0 关键词1.0 5.0 关键词2 10.0 关键词3 0.5 关键词46.0 规则是: 包含关键字1和关键字2的行应按该顺序排列,并在任何其他行之前 包含关键字3和关键字4的行可以是任意顺序 关键字1后面必须跟2 double 关键字2、3和4后面必须跟1个双精度 在包含所有四个关键字并后跟它们的double的行块末尾,“循环”中断并触发计算 以下是我的资料来源: using na

我需要阅读多行与特定的关键字在开始。 我有一个基本的问题,我需要帮助

以下是输入类型:

关键词1 0.0 0.0
关键词1.0 5.0
关键词2 10.0
关键词3 0.5
关键词46.0

规则是:

  • 包含关键字1和关键字2的行应按该顺序排列,并在任何其他行之前

  • 包含关键字3和关键字4的行可以是任意顺序

  • 关键字1后面必须跟2 double

  • 关键字2、3和4后面必须跟1个双精度

  • 在包含所有四个关键字并后跟它们的double的行块末尾,“循环”中断并触发计算

以下是我的资料来源:

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;
}
使用名称空间std;
int main(int argc,const char*argv[]){
矢量阵列;
弦线;
双关键字1_优先,关键字1_第二,关键字4,
关键词3,关键词2;
bool-inside\u-keyword1=false,after\u-keyword2=false,
关键字4_defined=false,关键字3_defined=false;
//cin.ignore();
while(getline(cin,line)){
如果(在关键字1内和关键字2和关键字3和关键字4后){
打破
}
其他的
{
std::istringstream拆分(行);
std::向量标记;
char split_char='';
for(std::string each;std::getline(split,each,split_char);tokens.push_back(each));
if(tokens.size()>2)
{
如果(令牌[0]!=“关键字1”)返回退出失败;//输入格式错误
其他的
{
关键词1_first=atof(令牌[1].c_str());
关键词1_second=atof(令牌[2].c_str());
inside_关键字1=真;
}
}
其他的
{
如果(令牌[0]=“关键字2”)
{
如果(内部关键字1)
{
关键字2=atof(令牌[1].c_str());
_关键字后2=真;
}
else返回EXIT_FAILURE;//无法在关键字1定义之后定义任何其他关键字2
}
else if(标记[0]=“关键字3”)
{
if(在关键字1内和关键字2后)
{
关键词3=atof(令牌[1].c_str());
关键词3_defined=true;
}
else返回EXIT_FAILURE;//无法在关键字1外部定义关键字3
}
else if(标记[0]=“关键字4”)
{
if(在关键字1内和关键字2后)
{
关键字4=atof(令牌[1].c_str());
关键词4_defined=true;
}
else返回EXIT_FAILURE;//无法在关键字1外部定义关键字4
}
}
}
}
//算计
//输出
返回退出成功;
}
我的问题是:除了在读取/解析循环中使用布尔函数外,还有没有更有效的方法来实现这一点?

您询问了一些“更有效”的问题,但似乎没有特定的性能目标。因此,您在这里想要的可能更像是代码复查。有这样一个网站,特别是:

但无论如何

你的直觉是正确的,这里并不真正需要四个布尔值。这就是2^4=16种不同的“状态”,其中许多状态你永远无法到达。(您的规范明确禁止,例如,
keyword3\u defined==true
在\u keyword1==false之后时)

当然,程序状态可以用枚举和布尔形式保存。这使得“健忘”循环可以在不同的情况下重新访问代码行,但仍然记得它处于哪个处理阶段。它在许多情况下都很有用,包括在复杂的解析器中。但是如果您的任务是线性且简单的,那么最好基于达到某一行代码来隐式地“了解”状态

作为一个教育性的例子来展示我所说的对比,这里有一个愚蠢的状态机,可以读取字母
a
,后跟任意数量的字母
B
s:

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
所有的状态变量都消失了。它们是不必要的,因为程序只是“知道它在哪里”。如果你重新思考你的例子,那么你可能也可以这样做。您不需要四个布尔值,因为您可以将光标放在一行代码上,自信地说出如果该行代码恰好正在运行,那么这四个布尔值必须是什么

<> P>效率,<>代码> /Cord>类可以使生活比这里更容易,更别称C++,而不调用C代码,如<代码> > <代码>,或者必须使用<代码> cx()/<代码>。让我们看一段代码的简化摘录,它只读取与“关键字1”相关联的双精度

魔法。Iostreams可以检测您尝试读取或写入的类型。如果它在按照您要求的方式解释输入时遇到问题,那么它会将输入留在缓冲区中,以便您可以尝试以另一种方式读取。(在请求字符串的情况下,行为是读取一系列字符,最大为空格……如果您确实需要整行,您可以像以前那样使用
getline

然而,错误处理是您必须处理的事情。可以告诉iostreams使用异常处理方法,因此遇到问题(例如,在预期出现双精度的地方出现随机字)的标准响应是使程序崩溃。但是默认设置是设置一个失败标志
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;