为什么 C++ 的文件 I/O 在读取文本文件时忽略初始空行?我怎样才能让它不这样做?
Why is C++'s file I/O ignoring initial empty lines when reading a text file? How can I make it NOT do this?
我正在尝试使用自己的自定义正则表达式和抽象语法树解析库 'srl.h'(又名“字符串和正则表达式库”)为自己构建一种小型编程语言,我发现我自己是一个我似乎不太明白的问题。
问题是这样的:当我的自定义代码遇到错误时,它显然会抛出一条错误消息,这条错误消息包含有关错误的信息,其中一位是抛出错误的行号。
问题在于 C++ 似乎完全忽略了不包含字符的行(即只是 CRLF 的行)的存在,直到它找到包含字符的行,之后点它停止忽略空行并正确对待它们,从而使所有错误抛出一个不正确的行号,它们都以相同的偏移量不正确。
基本上,如果给定一个包含内容“(crlf)(crlf)abc(crlf)def”的文件,它将被读取为好像其内容是“abc(crlf)def”,忽略初始新行,从而为抛出的所有错误报告错误的行号。
这是我用来获取文本文件文本的(各种编码混乱的)函数的副本。如果你们当中有人能告诉我这里发生了什么,那就太棒了。
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,因为它们最终进行了冗余迭代。
我正在尝试使用自己的自定义正则表达式和抽象语法树解析库 'srl.h'(又名“字符串和正则表达式库”)为自己构建一种小型编程语言,我发现我自己是一个我似乎不太明白的问题。
问题是这样的:当我的自定义代码遇到错误时,它显然会抛出一条错误消息,这条错误消息包含有关错误的信息,其中一位是抛出错误的行号。
问题在于 C++ 似乎完全忽略了不包含字符的行(即只是 CRLF 的行)的存在,直到它找到包含字符的行,之后点它停止忽略空行并正确对待它们,从而使所有错误抛出一个不正确的行号,它们都以相同的偏移量不正确。
基本上,如果给定一个包含内容“(crlf)(crlf)abc(crlf)def”的文件,它将被读取为好像其内容是“abc(crlf)def”,忽略初始新行,从而为抛出的所有错误报告错误的行号。
这是我用来获取文本文件文本的(各种编码混乱的)函数的副本。如果你们当中有人能告诉我这里发生了什么,那就太棒了。
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,因为它们最终进行了冗余迭代。