我正在尝试用自己定制的正则表达式和抽象语法树解析库“srl.h”(又名“字符串和正则表达式库”)为自己构建一种迷你编程语言,我发现了一个我似乎不太清楚的问题。
问题是这样的:当我的自定义代码遇到错误时,它显然会抛出一个错误消息,而这个错误消息包含有关错误的信息,其中一位是抛出错误的行号。
问题在于C++似乎只是完全忽略不包含字符的行的存在(即仅为CRLF的行),直到它找到一个包含字符的行,在这一点之后它停止忽略空行并正确地处理它们,从而给所有抛出的错误提供一个不正确的行号,它们都以相同的偏移量不正确。
基本上,如果给出一个包含内容“(crlf)(crlf)abc(crlf)def”的文件,它将被当作内容“abc(crlf)def”来读取,忽略初始的新行,从而为抛出的任何和所有错误报告错误的行号。
这里是我用来获取文本文件文本的(vary messily coded)函数的副本。 如果你们中有人能告诉我这里发生了什么,那就太好了。
template<class charT> inline std::pair<bool, std::basic_string<charT>> load_text_file(const std::wstring& file_path, const char delimiter = '\n') {
std::ifstream fs(file_path);
std::string _nl = srl::get_nlp_string<char>(srl::newline_policy);
if (fs.is_open()) {
std::string s;
char b[SRL_TEXT_FILE_MAX_CHARS_PER_LINE];
while (!fs.eof()) {
if (s.length() > 0)
s += _nl;
fs.getline(b, SRL_TEXT_FILE_MAX_CHARS_PER_LINE, delimiter);
s += std::string(b);
}
fs.close();
return std::pair<bool, std::basic_string<charT>>(true, srl::string_cast<char, charT>(s));
}
else
return std::pair<bool, std::basic_string<charT>>(false, std::basic_string<charT>());
}
std::ifStream::getLine()不将分隔符(在本例中为'\n')输入到字符串中,还将其从流中刷新,这就是为什么文件中的所有换行(包括前导行)在读取时被丢弃的原因。
程序似乎没有忽略其他行之间的换行是因为:
if (s.length() > 0)
s += _nl;
所有的换行实际上都是从这里来的,但是这不能在最开始的时候发生,因为字符串是空的。
这可以用一个小的测试程序来验证:
#include <iostream>
#include <fstream>
#include <string>
int main()
{
std::ifstream inFile{ "test.txt" }; //(crlf)(crlf)(abc)(crlf)(def) inside
char line[80]{};
int lineCount{ 0 };
std::string script;
while (inFile.peek() != EOF) {
inFile.getline(line, 80, '\n');
lineCount++;
script += line;
}
std::cout << "***Captured via getline()***" << std::endl;
std::cout << script << std::endl; //prints "abcdef"
std::cout << "***End***" << std::endl << std::endl;
std::cout << "Number of lines: " << lineCount; //result: 5, so leading /n processed
}
如果删除了If条件,那么程序只需:
s += _nl;
,将从文件中插入换行,而不是丢弃的行,但是只要'\n'是分隔符,std::ifStream::getLine()将继续丢弃原始行。
最后,我建议使用
while (fs.peek() != EOF){};
而不是
while(fs){};
或while(!fs.eof()){};
如果查看int linecount
在测试程序中的最终值,后两者给出的是6而不是5,因为它们最终会进行一次冗余迭代。