【问题标题】:Read in file with tabs and spaces用制表符和空格读入文件
【发布时间】:2018-03-03 03:48:24
【问题描述】:

我有一个这种格式的文本文件:

石油工程 94600 175500 海洋工程 73900 123200 经济与数学 60000 122900 地球物理 54100 122200 认知科学 54000 121900

我所拥有的是课程名称、职业早期平均工资和职业中期工资,所有这些都用制表符分隔。包含多个单词的课程名称以空格分隔。

我想读取课程名称并将其放入一个变量中,第一笔付款放入第二个变量中,第三笔付款放入第三个变量中。

    int main(){
        ifstream in;
        in.open("Salaries.txt");
        string course;
        int mid;
        int avg;
        if (in.fail()){
        cout<< "failed to open file";
        exit(1);
        }
        while(!in.eof()){
           in >> course >> avg >> mid;
           cout << course<<endl;
        }
      in.close();
     }

当我编译这段代码时,它什么也不输出,程序也没有退出或终止。

cmets中有人指出不推荐使用eof(),所以我改用了:

        while(in >> course >> sm >> lg){     
            cout << course << endl;
       }

进程退出而不向屏幕输出任何内容。我在一个看起来像这样的输入文件上进行了尝试:

核数 1 新 0 核心 100 输入 5000 核心 20

它获取字符串并将其放入一个变量中,并将数字放入另一个变量中,然后打印正确的输出。所以问题是原始文件中课程名称中的单词之间的空格,我不知道如何解释。

【问题讨论】:

  • 并且逐行调试显示程序在做什么?
  • 单步执行程序,看看它在哪里没有达到您的预期。想一想,查看变量值,找出原因。如果您想成为一名开发人员,学习调试是一项要求,而不仅仅是一个好主意。如果有某些正当理由不能使用调试器,请添加 print / cout / trace / logging 代码以获取相同的信息。
  • 保持while循环运行直到它到达文件的末尾@FeiXiang
  • @Dees:点击他提供的链接,然后阅读它指向的页面。

标签: c++ file io


【解决方案1】:

虽然您的代码确实存在其他问题,但您遇到的问题是 operator&gt;&gt;string 在遇到的第一个空白处停止读取。这意味着在第一行,它将Petroleum 读入course,然后尝试将Engineering 读入avg。由于avg 是一个数字,所以它不起作用,所以转换失败。从那里开始,从流中读取的所有进一步尝试都失败了。

要解决这个问题,您可能需要使用std::getline 来读取课程名称。它允许您指定将结束它读取的字符串的字符。在这种情况下,您显然想为该参数传递一个制表符 ('\t')。

如果我这样做,我可能会将这三个项目放入一个结构中,并为该结构重载 operator&gt;&gt;

struct course {
    std::string name;
    long early_pay;
    long mid_pay;

    friend std::istream &operator>>(std::istream &is, course &c) { 
        if (std::getline(is, c.name, '\t')) {
            std::string temp;
            std::getline(is, temp, '\t');
            c.early_pay = std::stol(temp);
            std::getline(is, temp);
            c.mid_pay = std::stol(temp);
        }
        return is;
    }
};

然后读取数据并打印出课程名称将如下所示:

int main() {
    std::istringstream input(
R"(Petroleum Engineering    94600   175500 
Marine Engineering  73900   123200 
Economics and Mathematics   60000   122900 
Geophysics  54100   122200 
Cognitive Science   54000   121900 )");

    course c;

    while (input >> c)
        std::cout << c.name << '\n';
}

【讨论】:

    【解决方案2】:

    使用std::getline() 从文件中读取行,并使用std::istringstream 解析每一行。然后,您可以使用std::getline() 从每一行读取制表符分隔的字符串。例如:

    int main() {
        ifstream in("Salaries.txt");
        if (!in.is_open()) {
            cout<< "failed to open file";
            exit(1);
        }
    
        string line course;
        int mid, avg;
    
        while (getline(in, line)) {
            istringstream iss(line);
            getline(iss, course, '\t');
            iss >> avg >> mid;
            cout << course << endl;
        }
    
        return 0;
    }
    

    【讨论】:

    • 我们使用stringstream而不是文件名有什么原因吗?
    • @Dees 外部循环上的getline 已将ifstream 推进到读取的行之外,因此您不能使用ifstream 来读取各个值。使用istringstream 允许从读取的行中解析值。您可以仅从 ifstream 本身读取值,但它的工作量更大,并且如果文件格式不正确,则可能会损坏解析。这种方式对一切都更安全。
    猜你喜欢
    • 2013-03-09
    • 2012-12-29
    • 1970-01-01
    • 2012-05-23
    • 2020-11-28
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2015-12-03
    相关资源
    最近更新 更多