0

请参阅下面的更新!

我的代码(现在我包含更多):

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
4

5 回答 5

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;
}
于 2012-12-03T05:13:11.133 回答
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您可以使用and my更轻松地执行相同的操作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*/});
于 2012-12-03T05:20:24.530 回答
0

目前还不清楚您要做什么。 std::getline 去除尾随的新行,因此无论何时输出已阅读的内容,都必须添加它。(如果您正在写入文本文件,如果写入的最后一个字符不是 .,则它是未定义的行为 '\n'。)

另请注意,您的主循环不正确。的状态 tasksClone.eof()是不确定的,在执行getline. 你需要的是这样的:

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

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

于 2012-12-03T09:38:26.543 回答
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;
        }
于 2012-12-05T23:59:59.410 回答
-1

如果您在 Windows 或 Mac 中查看文件,则问题可能在于使用“\n”。尝试改用“\r\n”。

于 2012-12-03T05:00:11.173 回答