当我将 .txt 文件加载到我的程序中时,如何删除这些随机整数(我根本没有输入)

Posted

技术标签:

【中文标题】当我将 .txt 文件加载到我的程序中时,如何删除这些随机整数(我根本没有输入)【英文标题】:How do i remove these random integers(which is I did not input at all) when I load a .txt file into my program 【发布时间】:2017-05-11 15:49:55 【问题描述】:

我目前正在用 C++ 做一个作业,我必须将一堆数据从 .txt 文件加载到一个链表中:

这是我的加载代码:

void record::load( string fileName ) throw( recordException )

    ifstream inFile( fileName.c_str() );
    string c;
    string t;
    double p;
    int q;
    node *tail;

    while (!isEmpty())
    
        remove( 1 );
    
    size = 0;

    if ( getline(inFile, c) ||getline(inFile,t)||inFile >> p>> q) // Is file empty?
      // File not empty:
        try
        
            head = new node;
            // Add the first integer to the list.
            head->cat = c;
            head->title = t;
            head->price = p;
            head->qty = q;
            head->next = NULL;
            tail = head;
            size = size + 1;
            inFile.skipws;

            // Add remaining items to linked list.
            while ( getline(inFile, c)||getline(inFile ,t)||inFile >> p>> q)
            // while(inFile.getline(c,50)||inFile.getline(t,50)||inFile>>p>>q)
            
                tail->next = new node;
                tail = tail->next;
                tail->cat = c;
                tail->title = t;
                tail->price = p;
                tail->qty = q;
                tail->next = NULL;
                size = size + 1;
                inFile.skipws;
              // end while
          // end try
        catch (bad_alloc e)
        
            throw recordException(
                "recordException: restore cannot allocate memory.");
          // end catch
      // end if

    inFile.close();

效果很好,除了一个问题:当我尝试显示加载到我的链接列表中的数据时,我得到了非常奇怪的数字。

这是我的程序运行时的样子:

谁能帮助我?我该怎么做才能删除这些数字?为什么会出现这些数字?

我正在使用 C++ Codeblocks 16.01,如果有帮助的话。

【问题讨论】:

if ( getline(inFile, c) ||getline(inFile,t)||inFile >> p>> q) 不应该是&& 而不是|| 使用调试器,例如gdb(并使用所有警告和调试信息进行编译,例如g++ -Wall -Wextra -g 文件实际上是什么样的?不管怎样,getline(inFile, c) || getline(inFile,t) || inFile >> p>> q 肯定不是读取文件的正确方法。显示数据的代码是什么样的? 我建议为您的节点类重载operator>>。节点应该能够从流中加载其成员,因为节点具有知识和直接访问权限。访问节点成员是违反封装规则的。 你不能这样分割那几行,你需要逐行阅读,然后使用 RE 或手动编写的逻辑分割。 【参考方案1】:

下次不要使用图片,而是将实际文本复制/粘贴到您的帖子中。

您的阅读代码与输入数据的格式不匹配。当您调用 getline() 时,它会一直读取直到遇到换行符或 EOF。

所以,对getline(inFile, c) 的第一次调用会一次性读取整个第一行:

"     DVD     Snow White          20     20"

然后getline(inFile,t) 一口气读取NEXT 行:

"     VCD     Cinderella          10     10"

然后inFile >> p >> q尝试解析NEXT行,失败:

"     MT      Wonderworld         20     30"

因为MT 不是double 并且Wonderworld 不是int

你需要逐行读取文件,单独解析每一行,例如:

#include <string>
#include <sstream>

void record::load( std::string fileName ) throw( recordException )

    while (!isEmpty())
        remove( 1 );
    size = 0;

    std::ifstream inFile( fileName.c_str() );
    if (!inFile.is_open())
        return;

    std::string line;
    std::string c;
    char t[25+1] = 0; // <-- use whatever your max title length actually is...
    double p;
    int q;
    node *newNode;

    while (std::getline(inFile, line)) // Is file empty?
    
        std::istringstream iss(line);

        if ((iss >> c) && iss.get(t, sizeof(t)) && (iss >> p >> qty))
        
            try
            
                newNode = new node;
                newNode->cat = c;
                newNode->title = t;
                newNode->price = p;
                newNode->qty = q;
                newNode->next = NULL;

                if (!head)
                    head = newNode;

                if (tail)
                    tail->next = newNode;
                tail = newNode;
                ++size;
            
            catch (const bad_alloc &e)
            
                throw recordException(
                    "recordException: restore cannot allocate memory.");
            
        
    

【讨论】:

【参考方案2】:

正则表达式更适合这样的任务。你可以使用类似的东西:

std::string test = "      DVD      Snow White       20    20";
std::regex re("\\s*(\\S+)\\s+(\\S.*\\S)\\s+(\\d+)\\s+(\\d+)");
std::smatch match;
if (std::regex_match(test, match, re)) 
        for (size_t i = 0; i < match.size(); ++i) 
            std::cout << "submatch " << i << ": \"" << match[i] << "\"\n";
           
  

live example

因此您可以逐行读取文件并使用该 RE 将其拆分:

std::regex re("\\s*(\\S+)\\s+(\\S.*\\S)\\s+(\\d+)\\s+(\\d+)");
std::string line;
while( std::getline( inFile, line ) ) 
    std::smatch match;
    if (!std::regex_match(test, match, re)) continue;
    std::string cat = match[1].str();
    std::string title = match[2].str();
    double price = std::stod( match[3].str() );
    int qty = std::stoi( match[4].str() );
    // you insert your node into list here 

注意:我根据您的输入制作了 RE 模式 - 价格仅包含数字,没有点。如果不是这种情况,则需要相应地修改 RE。

【讨论】:

以上是关于当我将 .txt 文件加载到我的程序中时,如何删除这些随机整数(我根本没有输入)的主要内容,如果未能解决你的问题,请参考以下文章

(Django)当我尝试将夹具文件加载到我的数据库中时,我不断收到字段冲突错误

无法加载或保存 txt。文件

将 png 加载到 UIImageView iOS

加载到 Hive 时从平面文件中删除单引号

如何让我的 QTableWidget 类(任何类)自行更新/刷新?

当图像保存在核心数据的集合视图中时,应用程序因内存错误而崩溃