如何从 C++ 中的文本文件中删除字符串的一部分[已关闭]

问题描述 投票:0回答:2

我正在尝试创建一个待办事项列表程序。

我在从txt文件中删除任务时遇到问题,我尝试从程序中读取所有数据并将某些数据替换为空白,但最终仍然留下了一些字符。

bool DoList::Remove_Task()
{
    std::ofstream temp_file("temp.txt", std::ios::app);
    std::ifstream file("Tasks_Data.txt");
    if (!temp_file.is_open())
    {
        std::cerr << "temp File cannot be opened to modify";
        return false;
    }
    else if (!file.is_open())
    {
        std::cerr << "File cannot be opened to read";
        return false;
    }
    else
    {
    int ID;
    int search;
    std::string TaskName;
    std::string Description;
    std::string Status;
    char str[26];
    std::string line;

    std::cout << "Enter Your Task ID to remove: ";
    std::cin >> search;

    while (getline(file, line))
    {
        while(file >> ID)

        if (ID == search)
        {

            ID = 0;
            TaskName = "\0";
            Description = "\0";
            Status = "\0";
            strcpy_s(str, "\0");
            temp_file << ID <<  ". " << std::setprecision(5) << TaskName << ", " << std::setprecision(5) << Description << ", " << std::setprecision(5) << Status << ", " << std::setprecision(5) << str << std::endl;
    
        }
        else
        {
            temp_file << line;
        }


    }
    }
    file.close();
    temp_file.close();

    remove("Tasks_Data.txt");
    rename("temp.txt", "Tasks_Data.txt");

    

    return true;
}
c++ file-handling
2个回答
3
投票

原代码:

std::ofstream temp_file("temp.txt", std::ios::app);

文件已打开以进行追加。如果先前的实例崩溃,文件将包含先前运行的数据。只需打开它即可写入。

原代码:

while (getline(file, line))
{
    while(file >> ID)

您已经读完了整行。

file >> ID
将从下一行读取ID。解析
line
以确定其 id。例如,您可以使用 std::stringstream:

int task_id;
std::stringstream(line) >> task_id;

原代码:

temp_file << ID <<  ". " << std::setprecision(5) << TaskName << ", " << std::setprecision(5) << Description << ", " << std::setprecision(5) << Status << ", " << std::setprecision(5) << str << std::endl;

对于不删除的行,您不需要解析它们并生成新的行。只需写下整行:

temp_file << line << std::endl;

原代码:

        return false;
    }
    else if (

如果前一个块从函数返回,则不需要

else
部分。

原代码:

    remove("Tasks_Data.txt");
    rename("temp.txt", "Tasks_Data.txt");

您不需要删除旧文件。

rename()
将原子地用新的替换它。

整个函数可能是这样的(

id
删除作为参数传递的参数,不检查格式错误):

bool Remove_Task(int id)
{
    std::ofstream temp_file("temp.txt");
    if (!temp_file.is_open())  {
        std::cerr << "temp File cannot be opened to modify";
        return false;
    }

    std::ifstream file("Tasks_Data.txt");
    if (!file.is_open()) {
        std::cerr << "File cannot be opened to read";
        return false;
    }

    std::string line;

    while (getline(file, line))
    {
        int task_id;
        std::stringstream(line) >> task_id;

        if (task_id != id) {
            temp_file << line << std::endl;
        }
    }

    file.close();
    temp_file.close();

    rename("temp.txt", "Tasks_Data.txt");

    return true;
}

2
投票

将您的问题分解为任务,将用户体验(读取和写入控制台)与访问数据(读取和写入文件)分开。

您需要的核心。该函数接受“行”(字符串)列表并删除具有指定任务 ID 的字符串。这个函数的神奇之处在于它只关心解析“行”,并找到行开头的前导数字。

bool RemoveTaskFromList(int taskIdToRemove, std::vector<std::string>& lines)
{
    bool found = false;
    for (auto itor = lines.begin(); itor != lines.end();)
    {
        std::string line = *itor;
        std::istringstream ss(line);
        int id;
        ss >> id;
        if (id == taskIdToRemove)
        {
            found = true;
            itor = lines.erase(itor); // returns a new iterator to "one past" what was just erased
        }
        else
        {
            itor++;
        }
    }

    return found;
}

请注意,上述函数不必将整行解析为组成部分。它只需要“读取”行开头的前导数字。它不是最强大的。如果该行不以数字开头,则

id
将被分配为零。您可以根据需要更改此设置。

另一个对文件执行实际 I/O 的函数(读取和写入磁盘)。它不需要了解有关各行格式的架构的任何信息。它只需要将所有行作为单独的字符串读取到字符串向量中。

bool RemoveTaskFromFile(int taskIdToRemove, const std::string& fileName, bool& ioError)
{
    std::ifstream ifile(fileName);
    ioError = false;
    if (!ifile)
    {
        ioError = true;
        return false;
    }

    // read all the lines
    std::vector<std::string> lines;
    std::string line;
    while(std::getline(ifile, line))
    {
        lines.push_back(line);
    }

    ifile.close();

    // remove the line
    bool found = RemoveTaskFromList(taskIdToRemove, lines);

    if (found == false)
    {
        return false;
    }

    // open the file again for writing
    std::ofstream ofile(fileName);
    if (!ofile)
    {
        ioError = true;
        return false;
    }

    // write all the lines back that were not removed from the vector
    for (const auto& line : lines)
    {
        ofile << line << "\n";
    }

    return true;
}

第三个与用户实际互动的功能:

bool DoRemove()
{
    int id;
    std::cout << "task id to remove\n";
    std::cin >> id;
    bool ioError;
    bool wasRemoved = RemoveTaskFromFile(id, "Tasks_Data.txt", ioError);
    if (ioError)
    {
        std::cout << "error reading or writing file\n";
    }
    else if (!wasRemoved)
    {
        std::cout << "can't find task in file\n";
    }
    else
    {
        std::cout << "successfully removed\n";
    }
    return wasRemoved;

}

这是一个练习,让您将其融入到

DoList
课程中。

© www.soinside.com 2019 - 2024. All rights reserved.