gpt4 book ai didi

c++ - 通过扫描关键字读取文本文件

转载 作者:太空宇宙 更新时间:2023-11-04 13:51:13 25 4
gpt4 key购买 nike

作为更大应用程序的一部分,我正在研究一个用于从文本文件读取输入以用于程序初始化的类。现在我对编程还很陌生,我只是在12月才开始学习C ++,所以我非常感谢您入门的一些提示和想法!我为很长的文字墙表示歉意。

文本文件格式采用以下方式“关键字驱动”:


需要以给定顺序编写的main / section关键字数量很少(目前为8个)。其中一些是可选的,但如果包含它们,则应遵循给定的顺序。


例:

假设有3个潜在关键字的顺序如下:

"KEY1" (required)
"KEY2" (optional)
"KEY3" (required)


如果输入文件仅包含必需的文件,则顺序应为:

"KEY1"
"KEY3"


否则应为:

"KEY1"
"KEY2"
"KEY3"



如果所有必需的关键字都存在,并且总排序正确,则程序应按顺序给出的顺序读取每个部分,以继续进行程序。
每个部分都将包含(可能很大量)子关键字,其中一些是可选的,而有些则不是,但是这里的顺序无关紧要。
以字符 '*''--'开头的行表示带注释的行,应将其忽略(以及空行)。
包含关键字的行应(最好)仅包含关键字。至少,关键字必须是在那里出现的第一个单词。


我已经实现了框架的各个部分,但是我觉得到目前为止我的方法是临时的。当前,我已经为每个section / main关键字手动创建了一个方法,该程序的首要任务是扫描文件以查找这些关键字并将必要的信息传递给这些方法。

我首先使用 std::ifstream对象浏览文件,删除空行和/或注释行,并将其余行存储在类型为 std::vector<std::string>的对象中。

您认为这是可以的方法吗?

此外,我将索引存储在此向量中每个关键字的开始和停止位置(两个整数数组)。这是上述方法的输入,看起来像这样:

bool readMAINKEY(int start, int stop);


现在,我已经做到了,尽管我觉得它不是很优雅,但我想我可以暂时保留它。

但是,我觉得我需要一种更好的方法来处理每一部分的内容,主要问题是如何在此处存储关键字?它们应该作为数组存储在输入类的本地名称空间中,还是作为静态变量存储在类中?还是应该在相关功能内部局部定义它们?我应该使用枚举吗?问题很多!

现在,我开始在每个 readMAINKEY()方法内部局部定义子关键字,但是我发现这并不是最佳选择。理想情况下,我想在每个方法中重用尽可能多的代码,并调用一个通用的 readSECTION()方法,而我目前的方法似乎会导致大量代码重复和编程错误。我想最聪明的事情就是删除所有(当前有8个)不同的 readMAINKEY()方法,并使用相同的函数来处理各种关键字。也可能有子关键字等(也就是更通用的嵌套方法),所以我认为这是可行的方法,但是我不确定如何最好地实现它?


一旦在“底层”处理了关键字,程序将根据实际关键字期望以下几行的特殊格式。原则上,每个关键字的处理方式都不同,但是根据触发该程序后读取该程序的期望定义不同的关键字“类型”,这里还存在一些代码重用的潜力。常见任务包括解析整数或双精度数组,但原则上可以是任何东西!
如果由于某种原因不能正确处理关键字,则程序应尽可能尝试使用默认值而不是终止程序(如果合理),但应将错误消息写入日志文件。对于可选关键字,当然也将使用默认值。


因此,为了总结一下,我的主要问题如下:

1.您认为我将相关行存储在 std::vector<std::string>中的方法是否合理?

当然,这将需要我做很多“索引工作”以跟踪不同关键字在向量中的位置。还是应该更直接地使用原始 std::ifstream对象?或者是其他东西?

2.给定这样一个存储文本文件各行的向量,我如何最好地检测关键词并开始阅读它们后面的信息?

在这里,我将考虑可能的排序以及是否需要关键字。另外,我需要检查每个“最低级别”关键字后面的行是否分别符合预期的格式。

我曾经有过一个想法,就是根据关键字是否可选(或使用 std::map<std::string,bool>类型的对象)将关键字存储在不同的容器中,如果处理正确,则将其从容器中删除,但我不确定应该如何处理。

我想确实有千种不同的方式可以回答这些问题,但是如果有经验的人可以分享一些有关如何进行的想法,我将不胜感激。是否有做这种事情的“标准”方式?当然,许多细节也将取决于具体的应用程序,但是我认为,此处指出的通用格式可以用于许多不同的应用程序,而如果以良好的方式进行编程,则无需进行很多修改!

更新

好的,让我尝试更具体些。我目前的应用程序应该是油藏模拟器,因此作为输入的一部分,我需要有关网格/网格,岩石和流体属性,整个模拟过程中的井/边界条件等信息。目前,我一直在考虑使用(几乎)与商业Eclipse模拟器相同的设置进行输入,有关详细信息,请参见
http://petrofaq.org/wiki/Eclipse_Input_Data

但是,我可能会有所改变,因此一无所获。另外,我对制作一个更通用的“ KeywordReader”类感兴趣,该类可以稍作修改就可以用于其他应用程序中,至少可以在合理的时间内完成。

举例来说,我可以发布当前代码,该代码对文本文件进行初始扫描并找到主要关键字的位置。正如我所说,我不太喜欢我的解决方案,但是它似乎可以满足其需要。

在.cpp文件的顶部,我具有以下名称空间:

//Keywords used for reading input:
namespace KEYWORDS{

/*
* Main keywords and corresponding boolean values to signify whether or not they are required as input.
*/
enum MKEY{RUNSPEC = 0, GRID = 1, EDIT = 2, PROPS = 3, REGIONS = 4, SOLUTION = 5, SUMMARY =6, SCHEDULE = 7};
std::string mainKeywords[] = {std::string("RUNSPEC"), std::string("GRID"), std::string("EDIT"), std::string("PROPS"),
std::string("REGIONS"), std::string("SOLUTION"), std::string("SUMMARY"), std::string("SCHEDULE")};
bool required[] = {true,true,false,true,false,true,false,true};
const int n_key = 8;

}//end KEYWORDS namespace


然后进一步向下,我具有以下功能。我不知道这是多么可理解。

bool InputReader::scanForMainKeywords(){

logfile << "Opening file.." << std::endl;

std::ifstream infile(filename);

//Test if file was opened. If not, write error message:
if(!infile.is_open()){
logfile << "ERROR: Could not open file! Unable to proceed!" << std::endl;
std::cout << "ERROR: Could not open file! Unable to proceed!" << std::endl;
return false;
}

else{

logfile << "Scanning for main keywords..." << std::endl;

int nkey = KEYWORDS::n_key;

//Initially no keywords have been found:
startIndex = std::vector<int>(nkey, -1);
stopIndex = std::vector<int>(nkey, -1);

//Variable used to control that the keywords are written in the correct order:
int foundIndex = -1;

//STATISTICS:
int lineCount = 0;//number of non-comment lines in text file
int commentCount = 0;//number of commented lines in text file
int emptyCount = 0;//number of empty lines in text file

//Create lines vector:
lines = std::vector<std::string>();

//Remove comments and empty lines from text file and store the result in the variable file_lines:
std::string str;
while(std::getline(infile,str)){
if(str.size()>=1 && str.at(0)=='*'){
commentCount++;
}
else if(str.size()>=2 && str.at(0)=='-' && str.at(1)=='-'){
commentCount++;
}
else if(str.size()==0){
emptyCount++;
}
else{
//Found a non-empty, non-comment line.
lines.push_back(str);//store in std::vector
//Start by checking if the first word of the line is one of the main keywords. If so, store the location of the keyword:
std::string fw = IO::getFirstWord(str);

for(int i=0;i<nkey;i++){
if(fw.compare(KEYWORDS::mainKeywords[i])==0){
if(i > foundIndex){
//Found a valid keyword!
foundIndex = i;
startIndex[i] = lineCount;//store where the keyword was found!
//logfile << "Keyword " << fw << " found at line " << lineCount << " in lines array!" << std::endl;
//std::cout << "Keyword " << fw << " found at line " << lineCount << " in lines array!" << std::endl;
break;//fw cannot equal several different keywords at the same time!
}
else{
//we have found a keyword, but in the wrong order... Terminate program:
std::cout << "ERROR: Keywords have been entered in the wrong order or been repeated! Cannot continue initialisation!" << std::endl;
logfile << "ERROR: Keywords have been entered in the wrong order or been repeated! Cannot continue initialisation!" << std::endl;
return false;
}
}
}//end for loop

lineCount++;
}//end else (found non-comment, non-empty line)
}//end while (reading ifstream)

logfile << "\n";
logfile << "FILE STATISTICS:" << std::endl;
logfile << "Number of commented lines: " << commentCount << std::endl;
logfile << "Number of non-commented lines: " << lineCount << std::endl;
logfile << "Number of empty lines: " << emptyCount << std::endl;
logfile << "\n";


/*
Print lines vector to screen:
for(int i=0;i<lines.size();i++){
std:: cout << "Line nr. " << i << " : " << lines[i] << std::endl;
}*/

/*
* So far, no keywords have been entered in the wrong order, but have all the necessary ones been found?
* Otherwise return false.
*/

for(int i=0;i<nkey;i++){
if(KEYWORDS::required[i] && startIndex[i] == -1){
logfile << "ERROR: Incorrect input of required keywords! At least " << KEYWORDS::mainKeywords[i] << " is missing!" << std::endl;;
logfile << "Cannot proceed with initialisation!" << std::endl;
std::cout << "ERROR: Incorrect input of required keywords! At least " << KEYWORDS::mainKeywords[i] << " is missing!" << std::endl;
std::cout << "Cannot proceed with initialisation!" << std::endl;
return false;
}
}

//If everything is in order, we also initialise the stopIndex array correctly:

int counter = 0;

//Find first existing keyword:
while(counter < nkey && startIndex[counter] == -1){
//Keyword doesn't exist. Leave stopindex at -1!
counter++;
}

//Store stop index of each keyword:
while(counter<nkey){

int offset = 1;

//Find next existing keyword:
while(counter+offset < nkey && startIndex[counter+offset] == -1){
offset++;
}


if(counter+offset < nkey){
stopIndex[counter] = startIndex[counter+offset]-1;
}
else{
//reached the end of array!
stopIndex[counter] = lines.size()-1;
}

counter += offset;
}//end while

/*
//Print out start/stop-index arrays to screen:
for(int i=0;i<nkey;i++){
std::cout << "Start index of " << KEYWORDS::mainKeywords[i] << " is : " << startIndex[i] << std::endl;
std::cout << "Stop index of " << KEYWORDS::mainKeywords[i] << " is : " << stopIndex[i] << std::endl;
}
*/

return true;

}//end else (file opened properly)
}//end scanForMainKeywords()

最佳答案

您说您的目的是从文本文件中读取初始化数据。
似乎您需要解析(语法分析)此文件并将数据存储在右键下。

如果语法是固定的,并且每个构造都以关键字开头,则可以编写一个递归下降(LL1)解析器,以创建一棵树(每个节点是子分支的stl向量)来存储数据。

如果语法是免费的,则可以选择JSON或XML并使用现有的解析库。

关于c++ - 通过扫描关键字读取文本文件,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/23295042/

25 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com