Так что я видел много решений на этом сайте и учебных пособий по чтению из текстового файла на C ++, но мне еще предстоит найти решение моей проблемы. Я новичок в C ++, поэтому я думаю, что у меня возникают проблемы с тем, чтобы собрать воедино часть документации, чтобы разобраться во всем этом.
То, что я пытаюсь сделать, это прочитать номера текстовых файлов, игнорируя при этом комментарии в файле, которые обозначены «#». Таким образом, файл примера будет выглядеть так:
#here is my comment
20 30 40 50
#this is my last comment
60 70 80 90
Мой код может хорошо читать цифры, когда нет комментариев, но я не понимаю, как анализировать поток достаточно хорошо, чтобы игнорировать комментарии. Это своего рода хакерское решение прямо сейчас.
/////////////////////// Read the file ///////////////////////
std::string line;
if (input_file.is_open())
{
//While we can still read the file
while (std::getline(input_file, line))
{
std::istringstream iss(line);
float num; // The number in the line
//while the iss is a number
while ((iss >> num))
{
//look at the number
}
}
}
else
{
std::cout << "Unable to open file";
}
/////////////////////// done reading file /////////////////
Есть ли способ, которым я могу включить обработку комментариев в это решение или мне нужен другой подход? Любой совет был бы отличным, спасибо.
Если ваш файл содержит #
всегда в первом столбце, затем просто проверьте, начинается ли строка с #
как это:
while (std::getline(input_file, line))
{
if (line[0] != "#" )
{
std::istringstream iss(line);
float num; // The number in the line
//while the iss is a number
while ((iss >> num))
{
//look at the number
}
}
}
Тем не менее, целесообразно обрезать линию начальных и конечных пробелов, как показано здесь, например: Удалить пробелы из std :: string в C ++
Если это только одно из применений, для линейно-ориентированного ввода, как у вас,
самое простое решение — просто убрать комментарий из строки, которую вы только что
читать:
line.erase( std::find( line.begin(), line.end(), '#' ), line.end() );
Более общим решением было бы использование фильтрующего потокового буфера, что-то
лайк:
class FilterCommentsStreambuf : public std::streambuf
{
std::istream& myOwner;
std::streambuf* mySource;
char myCommentChar;
char myBuffer;
protected:
int underflow()
{
int const eof = std::traits_type::eof();
int results = mySource->sbumpc();
if ( results == myCommentChar ) {
while ( results != eof && results != '\n') {
results = mySource->sbumpc(0;
}
}
if ( results != eof ) {
myBuffer = results;
setg( &myBuffer, &myBuffer, &myBuffer + 1 );
}
return results;
}
public:
FilterCommentsStreambuf( std::istream& source,
char comment = '#' )
: myOwner( source )
, mySource( source.rdbuf() )
, myCommentChar( comment )
{
myOwner.rdbuf( this );
}
~FilterCommentsStreambuf()
{
myOwner.rdbuf( mySource );
}
};
В этом случае вы могли бы даже отказаться getline
:
FilterCommentsStreambuf filter( input_file );
double num;
while ( input_file >> num || !input_file.eof() ) {
if ( ! input_file ) {
// Formatting error, output error message, clear the
// error, and resynchronize the input---probably by
// ignore'ing until end of line.
} else {
// Do something with the number...
}
}
(В таких случаях я считаю полезным также отслеживать номер строки в
FilterCommentsStreambuf
, Таким образом, у вас есть это за ошибку
Сообщения.)
Альтернативой «читать алине и анализировать его как строку» может быть использование самого потока в качестве входящего буфера:
while(input_file)
{
int n = 0;
char c;
input_file >> c; // will skip spaces ad read the first non-blank
if(c == '#')
{
while(c!='\n' && input_file) input_file.get(c);
continue; //may be not soooo beautiful, but does not introduce useless dynamic memory
}
//c is part of something else but comment, so give it back to parse it as number
input_file.unget(); //< this is what all the fuss is about!
if(input_file >> n)
{
// look at the nunber
continue;
}
// something else, but not an integer is there ....
// if you cannot recover the lopop will exit
}