C++读取文本文件时跳过注释和空行

引言

有时候我们需要自定义文件内容格式,然后从文本文件中读取数据或控制信息,在程序里面进行相应的处理。例如用文本文件存储空间点的坐标,设定文件的每一行有三个数,分别表示x y z,比如

0 0 0
1 2 3
2 3 3

表示(0, 0, 0), (1, 2, 3), (2, 3, 3)三个点。

由于文件里面的数据组织格式是自己定义的,别人不一定能看得懂,甚至过段时间之后自己都忘了。为了增强输入文件的可读性,最好能在文件中加入注释。如上面的坐标点文件加入注释后变成

#x y z, 单位:m
0 0 0 #第一个点 (0,0,0)
1 2 3 #意义同上
2 3 3 

这时候,在程序中读取文本文件的数据时就需要进行适当的处理,以达到跳过注释的效果。此外,文本文件中的空行有时候也会被错误的当作有效数据,因此读取文件时也要考虑跳过空行。

解决思路

读取文件时,以行为单位进行处理,用getline读取,如果有注释则先把注释删掉再进行处理。

  • 先读一行
    • 把该行的注释和开头的连续多个空格(以及tab)删掉
    • 读取数据
  • 读下一行
    • 处理注释,空格,空行

代码示例

用程序读取如下包含注释的文本文件,文件名为file

#这是一行注释,下面有两行空行


#x y z
0   0        2#第一个点

9,  9,	    10  #第二个点
11,  10		10         #第三个点
100,   0.9  3.1415926  #第四个点
10;	20;	30#第5个点,用分号作分隔符

程序代码如下:

#include <iostream>
#include<iomanip>
#include <string>
#include <sstream>
#include <fstream>
#include <cassert>
#include<vector>
using namespace std;

//处理注释,空格,和空行的函数
//line,表示一行文本内容
//comment_str,表示注释前导字符串,默认设置为#,也可以用//或者%
//string删除字串,http://www.cplusplus.com/reference/string/string/erase/
//string查找字串,http://www.cplusplus.com/reference/string/string/find_first_not_of/
void line_process(std::string &line, const std::string comment_str = "#")
{
    
    
    for (char &c : line)//C++11以上版本的语法
    {
    
    
        //制表符 tab,逗号,分号都当作有效的分隔符,统一转成空格
        //为了避免错误,回车符和换行符也转为空格(否则无法处理空行)
        if (c == '\t' || c == ',' || c == ';' || c == '\r' || c == '\n')
            c = ' ';
    }
   
    line.erase(0, line.find_first_not_of(" "));//删除行首空格
    line.erase(line.find_last_not_of(" ") + 1);//删除行末空格
    //调用的string& erase (size_t pos = 0, size_t len = npos);
    //len为默认参数
    
   
   //查找注释符所在位置,如果不存在,则得到string::npos
    int n_comment_start = line.find_first_of(comment_str); 
    if (n_comment_start != std::string::npos)//这一句必须的
        line.erase(n_comment_start);         //删除注释

    //处理完毕。如果这一行只有空格,制表符 tab,注释,那么处理后line为空;
    //如果行首有多个空格(或者空格和tab交错),行尾为注释,那么处理后字符串line的
    //行首多个空格(和tab)和行尾注释被删掉,只保留有意义的内容。
}

//举个栗子
int main()
{
    
    
    ifstream is("file");

    vector<double>x,y,z;
    x.clear();
    y.clear();
    z.clear();

    string line;
    while (std::getline(is, line))
    {
    
    
        line_process(line);//把行首和行尾的多个空格, tab去掉,把注释文字也去掉
        if (line.empty()) continue;//line为空则继续

        //根据实际需求处理
        std::istringstream iss(line);
        double x_temp,y_temp,z_temp;
        iss>>x_temp>>y_temp>>z_temp;
        x.push_back(x_temp);
        y.push_back(y_temp);
        z.push_back(z_temp);
    }

    //输出结果看看
    for(int i=0;i<x.size();i++){
    
    
        cout<<setw(12)<<x[i]
            <<setw(12)<<y[i]
            <<setw(12)<<z[i]<<endl;
    }
    return 0;
}

由于用到了C++11语法,编译器选项上要指定C++标准为C++11。如果上面程序文件名为test.cpp,所用编译器为g++,则在终端输入:

g++ -std=c++11 test.cpp -o test

得到名为test的可执行程序,然后运行:

./test

结果:

      0           0           2
       9           9          10
      11          10          10
     100         0.9     3.14159
      10          20          30

可以看到,程序读取时,成功地跳过了注释和空行,并且把分号,逗号,和tab都当成分隔符

扫描二维码关注公众号,回复: 12898271 查看本文章

猜你喜欢

转载自blog.csdn.net/X_And_Y/article/details/82081470