简体   繁体   中英

Parsing an edge list into a vector of structs

I am having a hard time parsing an edge list from a text file in c++. The edge list is in the following format:

*Edgeslist
1 6487
2 6488 6489 6490 6491 6492 6493 6494 6495 6496
3 6497 6498 6499 6500 6501 6502 6503 6504 6505
4 6506 6507 6508
5 6509 6510 6511
6 6512 6513 6514 6515
7 6516
8 6517 6518
9 6519 6520
10 6521 6522 6523 6524 6525 6526 6527 6528 6529 6530 6531 6532 6533 6534 6535
11 6566

My vector is a vector of structs that is defined here

struct Edge{
int character;
int edges[16];
};

The first number of each line should be read into the character integer and the rest should be read into the edges array. I have tried a few for loops, and currently working on a lengthy while loop with if statements for each number of possible integers to go into the array (max of 15 integers per line after the first number). Here is a part of my implementation so you can see what I am attempting.

while(std::getline(input, line))
{
  int a, b, c, d, e, f, g, h, i, j, k, l, m, n, o;
  std::stringstream ss(line);
  if ( ss >> a)
  {
       std::cout << "1 " << a << "\n";
  }
  if ( ss >> a >> b)
  {
       std::cout << "2 " << a << " " << b << "\n";
  }
  if ( ss >> a >> b >> c)
  {
       std::cout << "3 " << a << " " << b << " " << c << "\n";
  }
  if ( ss >> a >> b >> c >> d)
  {
       std::cout << "4 " << a << " " << b << " " << c << " " << d << "\n";
  }

I'll end it there but it does go on for awhile until it covers every possible line. At the moment I am just trying to figure out the basic logic to parse this text file.

You should split your string into substrings at whitespaces. Details are explained here.

After that, you just cast your substrings to appropiate type.

std::stringstream ss(line);
ss >> character;
unsigned int n=0;
while(ss >> edges[n])
{
  ++n;
}

(One could make this a little shorter, but that would make it less readable.)

You have tagged this as C++.

I would recommend you add an initializer if you must continue with pod ...

struct Edge
{
   int character;
   int edges[16];
   //  more data attributes

   // use ctor to initialize these values
   Edge(void) :
      character (0)
      // edges[16] 
   { 
      for (int i=0; i<16; ++i)
         edges[i] = 0;
   }


   // use dtor to clear them
  ~Edge(void)
   { 
      for (int i=0; i<16; ++i)
         edges[i] = 0;
      character = 0;
      // ...
   }

};

I suspect you will also need a count of how many edges have currently been in installed (or perhaps call it nextIn).


The fundamentally important signature of C++ code is the preferred use of objects-defined-by-a-class. I recommend you consider:

struct Edge
{
   int character;               // poor name choice
   std::vector<int> edges;      // << use vector, not array

   // use ctor to initialize these values
   Edge(void) :
      character (0)
      // edges   // default ctor does what you need
   { 
   }

   ~Edge(void) {
       // edges default dtor does what you need
       character = 0;
    }
};

The std::vector reduces your work to read arbitrary counts of values.

// Typical input:
// 3 6497 6498 6499 6500 6501 6502 6503 6504 6505
// 4 6506 6507 6508

#include <iostream>
#include <iomanip>
#include <sstream>
#include <vector>

struct Edge
{
   int character;               // <<< poor name choice
   std::vector<int> edges;      // <<< use vector, not array

   // use ctor to initialize these values
   Edge(void) :
      character (0)
      // edges  default ctor does what you need
      {
      }

   ~Edge(void) {
      // edges default dtor does what you need
      character = 0;
   }

   bool ok(void) {
      /*tbd - count errors? size check? */
      return(true);
   };

   void load(std::string line)
      {
         // typical input line
         // 3 6497 6498 6499 6500 6501 6502 6503 6504 6505
         // 4 6506 6507 6508

         std::stringstream ss(line+' ');
         // padding at end ---------^----because ss.eof() sooner than I expected

         //debug only
         //std::cout << "  in: (" << std::setw(3) << line.size() << ") 
         //          << line << std::endl;

         // process one work buff
         do {

            ss >> character; // read 1st int of line

            if (ss.eof()) break;

            if (ss.bad()) {
               // maybe invalid integer format
               std::cerr << "bad input: " << line << std::endl;
               // tbd - error count?
               break;
            }

            // process 1 or more entries for edge.vector from line
            do {

               int edgeVal = 0;

               ss >> edgeVal;

               if (ss.eof()) break;

               if (ss.bad()) {
                  // maybe invalid integer format
                  std::cerr << "bad input: " << line << std::endl;
                  // tbd - error count?
                  break;
               }

               // additional edgeVal validations?

               edges.push_back(edgeVal);  // fill in one value to edge vector

               // add validation here if edges.size() has an upper limit
               // tbd - error count?

            } while (1); // // process 1 or more entries to vector from line
         } while(1); // one work buff

         // debug only
         dump();

      }  // void load(std::stringstream& ss, std::string line)

   // for debug 
   void dump()
      {
         std::cout << "dump: (" << std::setw(3) << edges.size()
                   << ")  " << character << " ";

         for (size_t i=0; i<edges.size(); ++i)
            std::cout << edges[i] << " ";
         std::cout << std::endl;
      }

};  // struct Edge()



int t237(void)
{
   std::vector<Edge> edgeVec;

   // file processing at outer scope
   do {

      std::string line; // work buff

      (void)std::getline(std::cin, line);

      if(std::cin.eof()) break;

      std::stringstream ss(line);

      Edge temp; // a work buff

      temp.load(line); // <<< load method for Edge (part of Edge)

      // not sure where to put all the Edge objects
      // temporarily, use edgeVec;
      if (temp.ok())   // add flag check that edgeVec had no errors
         edgeVec.push_back(temp);
      else
         /*tbd*/{};  // error in temp ... discard it? report it?

   } while (1);

   // tbd - how return vector and file status

   return (0);
}

---- update

ss.eof() occurring before I expected ... added "padding at end" added dump() debug method, added debug cout of input line

minimal testing complete

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM