在我正在创建的控制台程序中,我有一些代码可以解析文件。解析每一行后,检查语法错误。如果存在语法错误,程序将停止读取文件并转到程序的下一部分。问题是,它非常混乱,因为到目前为止我唯一的解决方案是一系列嵌套的if语句或一行if语句。嵌套ifs的问题是它非常快速地变得非常混乱,并且一系列if语句对几个不需要测试的事情进行了程序测试。下面是我的问题的一些sudo代码(注意我没有使用return语句)
显示伪代码而不是真实代码,因为它非常大
嵌套if:
open file;
read line;
//Each if is testing something different
//Every error is different
if (line is valid)
{
read line;
if (line is valid)
{
read line;
if (line is valid)
{
do stuff;
}
else
error;
}
else
error;
}
else
error;
code that must be reached, even if there was an error;
非嵌套ifs:
bool fail = false;
open file;
read line;
//Each if is testing something different
//Every error is different
if (line is valid)
read line;
else
{
error;
fail = true;
}
if (!error && line is valid)
read line;
else
{
error;
fail = true;
}
if (!error && line is valid)
do stuff;
else
error;
//Note how error is constantly evaluated, even if it has already found to be false
code that must be reached, even if there was an error;
我查看了许多不同的网站,但他们的判断与我的问题不同。此代码在运行时可以正常工作,但正如您所看到的那样,它不是很优雅。是否有人对我的问题有更可读/更有效的方法?任何帮助表示赞赏:)
答案 0 :(得分:2)
有两种选择:
这与std::istream
提取运算符的工作方式类似。你可以这样做:
void your_function() {
std::ifstream file("some_file");
std::string line1, line2, line3;
if (std::getline(file, line1) &&
std::getline(file, line2) &&
std::getline(file, line3)) {
// do stuff
} else {
// error
}
// code that must be reached, even if there was an error;
}
这可能会有点长,但是如果你把事情分开(并给出一切正确的名字),它实际上可以非常易读和可调试。
bool step3(const std::string& line1,
const std::string& line2,
const std::string& line3) {
// do stuff
return true;
}
bool step2(std::ifstream& file,
const std::string& line1,
const std::string& line2) {
std::string line3;
return std::getline(file, line3) && step3(line1, line2, line3);
}
bool step1(std::ifstream& file,
const std::string& line1) {
std::string line2;
return std::getline(file, line2) && step2(file, line1, line2);
}
bool step0(std::ifstream& file) {
std::string line1;
return std::getline(file, line1) && step1(file, line1);
}
void your_function() {
std::ifstream file("some_file");
if (!step0(file)) {
// error
}
// code that must be reached, even if there was an error;
}
这个示例代码有点过于琐碎。如果在每个步骤中发生的行验证比std::getline
的返回值更复杂(在进行实际输入验证时通常就是这种情况),那么这种方法的好处是使其更具可读性。但是如果输入验证就像检查std::getline
一样简单,那么第一个选项应该是首选。
答案 1 :(得分:1)
一种常见的现代做法是早期回归RAII。基本上它意味着必须发生的代码应该在类的析构函数中,并且您的函数将具有该类的本地对象。现在当你遇到错误时,你可以从函数中提前退出(使用Exception
或只是return
),并且该本地对象的析构函数将处理必须发生的代码。
代码看起来像这样:
class Guard
{
...
Guard()
~Guard() { /*code that must happen */}
...
}
void someFunction()
{
Gaurd localGuard;
...
open file;
read line;
//Each if is testing something different
//Every error is different
if (!line)
{
return;
}
read line;
if (!line)
{
return;
}
...
}
答案 2 :(得分:1)
我的问题是否有更可读/更有效的方法
答案:一个编译器,它解析文本文件并产生不同类型的结果。
有很多方法和技巧。书籍,在线和开源示例。简单而复杂。
当然,如果你不感兴趣,你可能会跳过这一步。
通过这个理论,你不会错过像#34;状态机","自动化"以下是维基百科的简要说明:
https://en.wikipedia.org/wiki/Automata-based_programming
维基页面上基本上有一个现成的例子:
#include <stdio.h>
enum states { before, inside, after };
void step(enum states *state, int c)
{
if(c == '\n') {
putchar('\n');
*state = before;
} else
switch(*state) {
case before:
if(c != ' ') {
putchar(c);
*state = inside;
}
break;
case inside:
if(c == ' ') {
*state = after;
} else {
putchar(c);
}
break;
case after:
break;
}
}
int main(void)
{
int c;
enum states state = before;
while((c = getchar()) != EOF) {
step(&state, c);
}
if(state != before)
putchar('\n');
return 0;
}
或者是状态机的C ++示例:
#include <stdio.h>
class StateMachine {
enum states { before = 0, inside = 1, after = 2 } state;
struct branch {
unsigned char new_state:2;
unsigned char should_putchar:1;
};
static struct branch the_table[3][3];
public:
StateMachine() : state(before) {}
void FeedChar(int c) {
int idx2 = (c == ' ') ? 0 : (c == '\n') ? 1 : 2;
struct branch *b = & the_table[state][idx2];
state = (enum states)(b->new_state);
if(b->should_putchar) putchar(c);
}
};
struct StateMachine::branch StateMachine::the_table[3][3] = {
/* ' ' '\n' others */
/* before */ { {before,0}, {before,1}, {inside,1} },
/* inside */ { {after, 0}, {before,1}, {inside,1} },
/* after */ { {after, 0}, {before,1}, {after, 0} }
};
int main(void)
{
int c;
StateMachine machine;
while((c = getchar()) != EOF)
machine.FeedChar(c);
return 0;
}
当然,你应该用线来代替字符。
这种技术可扩展到复杂的编译器,经过大量实现验证。所以,如果你正在寻找一个&#34;权利&#34;方法,在这里。