Как проверить, если EOF (после использования getline)

Смотрите обновление ниже!

Мой код (теперь я включил больше):

while(getline(checkTasks, workingString)){
countTheDays = 0;
// Captures a clean copy of the line in tasks.dat in it's entirety, stores in workingString.
char nlcheck;
checkTasks.get(nlcheck);
if(nlcheck == '\n'){
}
else{
checkTasks.unget();
//getline(checkTasks, workingString);
// Breaks that line up into more usable pieces of information.
getline(check2,tName, '\t');
getline(check2,tDate, '\t');
getline(check2,trDate, '\t');
getline(check2,tComplete, '\n');
// Converts the string form of these pieces into usable integers.
stringstream(tDate.substr(0,tDate.find_first_of('/'))) >> year;
stringstream(tDate.substr(tDate.find_first_of('/')+1,tDate.find_last_of('/'))) >> month;
stringstream(tDate.substr(tDate.find_last_of('/')+1,tDate.length()-1)) >> day;
stringstream(tComplete) >> checkComplete;
stringstream(trDate) >> checkReminder;

// Adds the number of days until your task is due!
if(year != date[0]){
for(int i = date[1]; i <= 12; i++){
countTheDays += System::DateTime::DaysInMonth(date[0], i);
}
countTheDays-= date[2];
for (int i = 1; i<= month; i++){
countTheDays +=System::DateTime::DaysInMonth(year, i);
}
countTheDays -= (System::DateTime::DaysInMonth(year, month) - day);
}
else if(month != date[1]){
for(int i = date[1]; i <= month; i++){
countTheDays += System::DateTime::DaysInMonth(date[0], i);
}
countTheDays -= (date[2]);
countTheDays -= (System::DateTime::DaysInMonth(year, month) - day);
}
else{
countTheDays+= System::DateTime::DaysInMonth(date[0], month);
countTheDays -= (System::DateTime::DaysInMonth(year, month) - day);
countTheDays -= date[2];
}

// If the task is nearing it's due date (the time frame specified to be notified) it'll notify user.
// Only coded to work if the task is due in the current or following months.
if(countTheDays <= checkReminder){
if( countTheDays < 0){
cout << endl << endl << tName << " is past due!" << endl;
cout << "Should I keep reminding you about this task? Enter Y or N. ";
cin >> continueToRemind;
}
else{
cout << endl << endl << tName << " is due in " <<countTheDays << " days! Don't forget!" << endl;
cout << "Should I keep reminding you about this task? Enter Y or N. ";
cin >> continueToRemind;
}

// If user doesn't want to be reminded, begins process of converting that line in the file to usable info
// and 'overwriting' the old file by creating a new one, deleting the old one, and renaming the new one.
if(continueToRemind == "n" || continueToRemind == "N"){
fileModified = true;
string line;
/*  vector<string> lines;
while(getline(tasksClone, line)){
lines.push_back(line);
}
lines.erase(remove(lines.begin(), lines.end(), workingString), lines.end());
if (!lines.empty()) {
auto i=lines.begin();
auto e=lines.end()-1;
for (; i!=e; ++i) {
saveTasks << *i << '\n';
}
saveTasks << *i;
}*/// This writes a copy of the tasks.dat file, minus the task that the user elected not to be notified of.'
while(getline(tasksClone, testBuffer)){
if(testBuffer == workingString){
// This condition does nothing. Essentially erasing the 'completed' task from the list.
}
else if(testBuffer != workingString && tasksClone.eof()){
// This writes everything except the specified task to taskbuffer.dat
saveTasks << testBuffer;
}
else {
saveTasks << testBuffer << '\n';
}
}
}
}
}
}
}
else{
cout << "The tasks file is empty, you must not have any tasks!" << endl;
}

Я надеюсь, что этот вопрос имеет смысл!

Спасибо

Маркус

ОБНОВЛЕНИЕ: снова переработан код. После того, как он сказал удалить одну задачу, он никогда не запускает этот цикл. Текущий код:

while(getline(tasksClone, testBuffer)){
if(testBuffer == workingString){
// This condition does nothing. Essentially erasing the 'completed' task from the list.
}
else if(testBuffer != workingString && tasksClone.eof()){
// This writes everything except the specified task to taskbuffer.dat
saveTasks << testBuffer;
}
else {
saveTasks << testBuffer << '\n';
}

}

Входной файл:

test1   2012/12/13  10  0;
test2   2012/12/23  20  0;
test3   2012/12/31  28  0;
\n

Выходной файл (после указания удалить test1 и 2):

test2   2012/12/23  20  0;
test3   2012/12/31  28  0;
\n

0

Решение

Первое, что я хотел бы сделать, это просто прочитать весь ваш файл в вектор строк, каждая строка соответствует строке в файле. Это можно сделать довольно легко.

std::vector<std::string> lines;
std::string line;
while (std::getline(tasksClone, line))
lines.push_back(line);

Как только вы это сделаете, обработка станет намного проще. Вы можете проверить, пуста ли строка, например:

if (lines[i].empty())

Это эквивалентно проверке, является ли следующий символ после новой строки другой новой строкой. Вы можете удалить любые строки из вектора, которые вам не нужны, например:

lines.erase(std::remove(lines.begin(), lines.end(), workingString), lines.end());

Однако вместо этого вы могли бы избежать размещения их в векторе, поместив тест в цикл, который считывает строки из файла.

После того, как вы выполнили всю свою обработку, вы можете просто записать строки обратно в другой файл, вставив новые строки вручную.

if (!lines.empty()) {
auto i=lines.begin(), e=lines.end()-1;
for (; i!=e; ++i) {
saveTasks << *i << '\n';
}
saveTasks << *i;
}
0

Другие решения

Вместо добавления новой строки в конце каждой строки, но только если есть еще одна строка для записи, я бы просто предшествовать каждая строка новой строкой. Это даст вам новую строку в начале файла, а не новую строку в конце, как вы хотите.

Как обычно, код вроде while (!your_file.eof()) сломан, хотя. Вы, вероятно, хотите что-то вроде:

while (std::getline(taskClone, buffer)) {
if (buffer.empty())
continue;

if (keep(buffer)) // whatever condition you need
saveTasks << "\n" << buffer;
}

Вы можете сделать то же самое немного легче с std::remove_copy_if и мой ostream_prefix_iterator:

// prefix_iterator.h
#include <ostream>
#include <iterator>

template <class T,
class charT=char,
class traits=std::char_traits<charT>
>
class prefix_ostream_iterator :
public std::iterator<std::output_iterator_tag,void,void,void,void>
{
charT const* delimiter;
std::basic_ostream<charT,traits> *os;
public:
typedef charT char_type;
typedef traits traits_type;
typedef std::basic_ostream<charT,traits> ostream_type;

prefix_ostream_iterator(ostream_type& s)
: os(&s),delimiter(0)
{}
prefix_ostream_iterator(ostream_type& s, charT const *d)
: os(&s),delimiter(d)
{}
prefix_ostream_iterator<T,charT,traits>& operator=(T const &item)
{
// Here's the only real change from ostream_iterator:
// Normally, the '*os << item;' would come before the 'if'.
if (delimiter != 0)
*os << delimiter;
*os << item;
return *this;
}

prefix_ostream_iterator<T,charT,traits> &operator*() {
return *this;
}
prefix_ostream_iterator<T,charT,traits> &operator++() {
return *this;
}
prefix_ostream_iterator<T,charT,traits> &operator++(int) {
return *this;
}
};

Используя это вместе с line прокси я разместил в более ранний ответ, Вы можете сделать работу с кодом что-то вроде:

#include "line.h"#include "prefix_iterator.h"
std::remove_copy_if(std::istream_iterator<line>(taskClone),
std::istream_iterator<line>(),
prefix_ostream_iterator<std::string>(taskSave, "\n"),
[](std::string const &line) { /* decide if to keep line*/});
0

Не очень понятно, что вы пытаетесь сделать. std::getline
удаляет завершающую новую строку, так что каждый раз, когда вы выводите то, что вы
прочитайте, вы должны добавить его. (Если вы пишете в текстовый файл,
это неопределенное поведение, если последний написанный символ не
'\n'.)

Обратите внимание, что ваш основной цикл неверен. Штат
tasksClone.eof() является неопределенным, и вы не проверяете, что
после успешного завершения ввода getline, Что ты
нужно что-то вроде:

std::string line
while ( std::getline( tasksClone, line ) ) {
if ( line != workingString ) {
saveTasks << line << '\n';
}
}

В вашем примере ввода первая прочитанная строка будет пустой.

0

Я решил свою проблему, на случай, если кто-то захочет узнать. Это не так эффективно для памяти, как могло бы быть, но оно функционирует:

// Reads the file, checks if it's due, and if it's due prompts user to either save or delete the task.
// Captures a clean copy of the line, in its entirety, and stores it to workingString.
while(getline(checkTasks,workingString)){
countTheDays = 0;
// Handles newline characters.
char nlcheck;
checkTasks.get(nlcheck);
if(nlcheck == '\n'){
}
else{
checkTasks.unget();
// Breaks that line up into more usable pieces of information.
getline(check2,tName, '\t');
getline(check2,tDate, '\t');
getline(check2,trDate, '\t');
getline(check2,tComplete, '\n');
// Converts the string from of these pieces into usable integers.
stringstream(tDate.substr(0,tDate.find_first_of('/'))) >> year;                       stringstream(tDate.substr(tDate.find_first_of('/')+1,tDate.find_last_of('/'))) >> month;                  stringstream(tDate.substr(tDate.find_last_of('/')+1,tDate.length()-1)) >> day;
stringstream(tComplete) >> checkComplete;
stringstream(trDate) >> checkReminder;

// Adds the number of days until your task is due!
if(year != date[0]){
for(int i = date[1]; i <= 12; i++){
countTheDays += System::DateTime::DaysInMonth(date[0], i);
}
countTheDays-= date[2];
for (int i = 1; i<= month; i++){
countTheDays +=System::DateTime::DaysInMonth(year, i);
}
countTheDays -= (System::DateTime::DaysInMonth(year, month) - day);
}
else if(month != date[1]){
for(int i = date[1]; i <= month; i++){
countTheDays += System::DateTime::DaysInMonth(date[0], i);
}
countTheDays -= (date[2]);
countTheDays -= (System::DateTime::DaysInMonth(year, month) - day);
}
else{
countTheDays+= System::DateTime::DaysInMonth(date[0], month);
countTheDays -= (System::DateTime::DaysInMonth(year, month) - day);
countTheDays -= date[2];
}

// If the task is nearing it's due date (the time frame specified to be notified) it'll notify user.
if(countTheDays <= checkReminder){
if( countTheDays < 0){
cout << endl << endl << tName << " is past due!" << endl;
cout << "Should I keep reminding you about this task? Enter Y or N. ";
cin >> continueToRemind;
}
else{
cout << endl << endl << tName << " is due in " <<countTheDays << " days! Don't forget!" << endl;
cout << "Should I keep reminding you about this task? Enter Y or N. ";
cin >> continueToRemind;
}

// If user doesn't want to be reminded, begins process of converting that line in the file to usable info
// and 'overwriting' the old file by creating a new one, deleting the old one, and renaming the new one.
if(continueToRemind == "n" || continueToRemind == "N"){
fileModified = true;
// Adds workingString to deleteTasks[] to be compared against later.
deleteTasks.push_back(workingString);
}
}
}
}

int match = 0;
// Iterates through tempTasks.dat and compares lines to workingString.
while(getline(tasksClone, testBuffer)){
for(int i = 0; i< deleteTasks.size(); i++){
// If a match is found, it sets the match flag to delete that line.
if(testBuffer ==  deleteTasks[i]){
match = 1;
}
}
// Deletes that task.
if(match == 1){
//Do nothing, erasing the task
}
// If EOF, writes only the task, without a newline character.
else if(tasksClone.eof()){
saveTasks << testBuffer;
}
// If !EOF, also writes a newline character.
else{
saveTasks << testBuffer << '\n';
}
match = 0;
}
0

Проблема может заключаться в использовании «\ n», если вы просматриваете файлы в Windows или Mac.
Попробуйте вместо этого использовать «\ r \ n».

-1
По вопросам рекламы ammmcru@yandex.ru
Adblock
detector