繁体   English   中英

如何检查EOF(使用getline之后)

[英]How to check if EOF (after using 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;
    }

我希望这个问题有道理!

谢谢

马库斯

更新:重新编写代码。 告诉它删除1个任务后,它将永远不会运行此循环。 当前代码:

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

我要做的第一件事就是将整个文件读入一个字符串向量中,每个字符串对应于文件中的一行。 这很容易做到。

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;
}

而不是在每行的末尾添加换行符,而是仅在随后要写另一行时,我才每行之前加上换行符。 这将使您在文件的开头获得换行符,而在结尾处没有换行符。

与往常一样, 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*/});

目前尚不清楚您要做什么。 std::getline会删除尾随的新行,因此,每当您输出已阅读的内容时,都必须添加它。 (如果要写入文本文件,则最后写入的字符不是'\\n' ,这是未定义的行为。)

还要注意,您的主循环是不正确的。 tasksClone.eof()的状态是不确定的,在执行getline之后,您不会验证输入是否成功。 您需要的是这样的:

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

在示例输入中,您读取的第一行将为空。

我解决了我的问题,以防万一有人想知道。 它的内存效率不尽如人意,但可以发挥作用:

// 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;
        }

如果您在Windows或Mac中查看文件,则可能是使用“ \\ n”引起的。 尝试改用“ \\ r \\ n”。

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM