如何避免在文本文件中阅读评论?

时间:2015-07-10 05:39:05

标签: c++ parsing input output readfile

目前我已成功使用此代码向我的文件写入0到10之间的一些随机数(下面只是一些示例代码来演示问题):

for (int i = 1; i <= size; i++)
{
    type = rand () % 3;
    switch (type)
    {
    case 0:  afile << rand () % 10;
             break;
    case 1:  afile << rand () % 10;
             afile << "\t\t";
             afile << rand () % 10;
             break;
    case 2:  afile << rand () % 10;
             afile << "\t\t";
             afile << rand () % 10;
             afile << "\t\t";
             afile << rand () % 10;
             /*afile << "8";
             afile << "\t";
             afile << "7";
             afile << "\t";
             afile << "2";*/
    }

    afile << "\t\t" << "// Possible type " << i << endl;
}

然后我的afile在执行代码后看起来像这样:

8       // Possible type 1
1       7       // Possible type 2
4       0       3       // Possible type 3

当我从此文件读取数据并输出到另一个文件时,会出现问题:

int type;

while (afile >> type)
{
    if(type == 0) 
    {
        afile >> .........;
        ..........
    } 
        else if(type == 1) {.........}
        else if(type == 2) {.........}
    }       
}
...................................... 

我的输出文件在第一行后停止读取,因为它还读取了要处理的无效数据的注释,如果我删除注释,那么一切正常。那我怎么能克服这种情况呢?谢谢。

3 个答案:

答案 0 :(得分:3)

Tony D已经提供了一个合理的答案,但我认为我也添加了自己的代码,因为我已经编写并测试了它。

对于任何说C ++的人来说,下面几乎是不言自明的,它基本上是Tony提出的,但有一个转折 - 逐行获取数据,利用std::stringstream但随后也利用了OP使用的数据的二进制特性。那里的数据是有效的整数或注释。或者换句话说,是否为有效整数。因此,在下面的代码中,无法将数据从流转换为整数 - 该行的其余部分将被视为注释。编辑:...实际上,当它是一个有点有效的解决方案,我修改了代码以包含一个更健全的方法 - 一个跳过评论(由#//表示以显示两种方法)但仍然让我们决定做什么做错了价值。这不允许45fubar传递为45,然后传递错误fubar,这是前一代码的问题,但允许正确解释45//comment

我仍然认为直接切断\/\/.*?是一种更好的方法。这个答案的重点是有点不同。 ;)

#include <ctime>
#include <cmath>
#include <string>
#include <iostream>
#include <sstream>
#include <fstream>
#include <vector>

void write(std::ostream& output, int lines) {
    for (int i = 0; i < lines; i++) {  // for i lines
        int n = rand() % 10 + 1;       // generate n numbers per line
        for (int j = 0; j < n; j++) {  // loop over line
            output << rand() % 99;     // output a random number
            if (j + 1 < n) {           // if not last?
                output << "\t\t";      // then add tabs
            }
        }
        output << " // " << n << " numbers\n"; // I'm not using std::endl here because it actually *flushes* the stream - flushing every iteration isn't advisable
    }
}

std::vector<std::vector<int>> read(std::istream& input) {
    std::vector<std::vector<int>> v;           // a vector of vectors of ints
    std::string line;               
    while (std::getline(input, line)) {        // getline returns the stream by reference, so this handles EOF
        std::stringstream ss(line);            // create a stringstream out of line
        int n = 0;                          
        std::vector<int> numbers_in_line;
        while (ss) {                           // while the stream is good
            std::string word;
            if (ss >> word) {                  // if there's still data to get
                std::stringstream tester(word);
                tester >> n;
                if (tester && tester.peek() == std::char_traits<char>::eof()) { // conversion went well, no data was left in stream
                    numbers_in_line.push_back(n);   // push it to the vector
                } else {         // conversion didn't go well, or went well but data was left in the stream
                    bool conversion_went_well = tester.good();
                    tester.clear();
                    char c = tester.get();
                    if (c == '#' || (c == '/' && tester.peek() == '/')) { // if it's a comment
                        if (conversion_went_well) {
                            numbers_in_line.push_back(n);                 // push it to the vector
                        }
                        break;                                            // and ignore the rest of the line
                    } else {
                        std::cerr << "Unexpected symbol: '" << tester.str() << "'\n"; // report unexpected data
                        //  so how do we handle a malformed value?
                        //  error out? ignore following values in this line? accept following values in this line?
                        // if you leave it as is now - it will accept following values from this line
                    }

                } 
            }
        }
        v.push_back(numbers_in_line);       
    }

    return v;
}

int main(int argc, char** argv) {
    std::srand(std::time(nullptr));
    write(std::cout, 4);                                    // write random data
    std::vector<std::vector<int>> numbers = read(std::cin); // read the data

    for (std::vector<int> line: numbers) {  // loop over vector via C++11 features
        for (int n: line) {
            std::cerr << n << " ";
        }
        std::cerr << "\n";
    }

    return 0;
}

示例运行:

$ ./test.exe < data > data
50 44 92 43 97
26 32 54
30 91
93 4
$ cat data
50      44      92      43      97 // 5 numbers
26      32      54 // 3 numbers
30      91 // 2 numbers
93      4 // 2 numbers


$ ./test.exe < data2 > dump
Unexpected symbol: 'i91'
Unexpected symbol: '4i'
Unexpected symbol: 'lol'
Unexpected symbol: 'numbers'
50 44 92 43 97
26 32 54
30
93 3 2
7337
7337
$ cat data2
50      44      92      43      97 // 5 numbers
26      32      54 # 3 numbers
30      i91 // 2 numbers
93      4i      lol 3 2 numbers
7337//test comment
7337#test comment 2

答案 1 :(得分:1)

有几种方法可以做到这一点。

找到报价后跳过剩余的一行(更快)

基本上你在这里做的是在循环中逐行读取文件。当你点击两个字符&#34; //&#34;。你打电话给#34;打破;&#34;并跳到下一行。&#39;

一些未经测试的虚拟代码:

while(line = file.getLine()){
  loopChars = sizeof(line);
  for(x = 0; x < loopChars; x++) {
    char currentChar = line[x];
    if(x+1 < loopChars){
       char nextChar = line[x+1];
    } else {
       char nextChar = '';
    }

    if(nextChar == "/" && currentChar == "/"){
      // Go to next line 
      break; 
    } else {
      // Do your normal processing here
    }
  }
}

先删除行情(较慢)

以下是从文件中删除引号(一个内衬&#34; //&#34;以及多行&#34; / ** /&#34;)的解决方案。基本上,在开始读取数字数据之前,您可以针对正在处理的文件运行此文件。

http://www.cplusplus.com/forum/beginner/80380/

#include <iostream>
#include <fstream>
using namespace std;

int main (){
    ifstream infile;
    string filename;
    ofstream outfile;
    char c1, c2;
    bool isInsideComment = false;

    cout << "Please input file name (to remove comments from): ";
    cin >> filename;

    infile.open (filename.c_str());
    if (infile.fail()) {
        cout << "nInvaild file name.n";
        return 1;
    }
    outfile.open(("out_"+filename).c_str());

    infile.get (c1);
    while (!infile.eof()) {
        if ((c1 == '/') && (!isInsideComment)) {
            infile.get (c2);
            if (c2 == '*')
            isInsideComment = true;
            else if ((c1 == '/') && (c2 == '/'))
            isInsideComment = true;
            else {
                outfile.put (c1);
                outfile.put (c2);
            }
        }

        else if ( (c1 == '*') && isInsideComment) {
            infile.get (c2);
            if (c2 == '/')
            isInsideComment = false;
            else if ((c1 == 'n') && isInsideComment)
            isInsideComment = false;
        }
        else if (!isInsideComment)
        outfile.put (c1);
        infile.get (c1);
    }
    infile.close();
    outfile.close();
}

答案 2 :(得分:1)

你有几个合理的选择:

  • 将整行读入std::string,扫描并删除任何评论,然后从左边的任何内容创建std::istringstream并从中提取,以提取非评论值

  • 在阅读数值之前,请使用>> std::wsafile.peek()查看下一个字符是否为'/':如果是,请跳过,直至到达换行符。

    < / LI>

前者是一种习惯于在C ++中使用的有用技术(当您想要报告包含数据问题的行号时有帮助),如下所示:

if (std::ifstream in(filename))
{
    std::string line;
    while (getline(in, line))
    {
        std::string::size_type n = line.find("//");
        if (n != std::string::npos)
            line.erase(n);

        std::istringstream iss(line);

        int atype;
        while (iss >> atype)
            ...etc...
    }