繁体   English   中英

从逗号分隔的数据文件 C++ 中读取列

[英]Read columns from a comma delimited data file c++

我一直在尝试阅读以下数据表并为 HUB(行)创建一个对象,为大陆(列)创建另一个对象。 由于我不是 C++ 经验丰富的用户,因此我一直面临一些困难。 数据如下。 HUB 和破折号后面的数字表示从集线器开始的顺序。 每个大洲下的其他数字是 HUB 和大洲之间的相应成本和资费。 我希望能够 cout 例如跟随并得到 73 的结果。 cout << hub(1)->cont(USA)->transport() << endl;

,USA,EUROPE,ASIA
HUB1-12000,,,
Transportation Cost,73,129,141
Tariffs,5,5,1
ShippingType,a,b,c
OtherFees,0.6,0.3,0.8
HUB2-11000,,,
Transportation Cost,57,101,57
Tariffs,7,7,5
ShippingType,b,b,d
OtherFees,0.7,0.3,0.6

真的很感谢你的帮助。 这是我迄今为止尝试过的:

    void Hub()
   {
     string file = "/hubs.csv";         

     // 1-First read the first line and save the continent name
     string str, field;
     getline( fin, str );
     vector<string> contList;
     stringstream linestr( str );
     while (  linestr.good() )
     {
       getline( linestr, field, ',' );
       string contname;
       contList.push_back(contname);
     }

     // 2-Then read the rest
     getline( fin, str );
     while ( !fin.eof() )  // Read the whole file
     {
       stringstream linestr( str );
       string contname, order;
       if ( qstr[0] == 'HUB1' || qstr[0] == 'HUB2')         
       {
         // Read the name of the hub
         getline( linestr, hubname, ',' );           // Read the hub name
         getline( linestr, order, ',' );             // Read the order quantityity

         int quantity;
         istringstream orderstream( order);
         orderstream >> quantity;

         // Find the hub and add the order to the hub
         Hub* hub = glob->FindHubName( hubname ); // this returns a pointer 
         if ( glob->FindHubName( hubname ) == nullptr )
         {
           hubNotFound.push_back( hubname );
           getline( fin, qstr );
           continue;
         }
         hub->TotalOrder( quantity );
       }
       else if ( qstr[0] != 'HUB1' || qstr[0] != 'HUB2')   
       {
         // Read costs and tariffs 
         cout << hub(1)->cont(ASIA)->transport() 
        }
       getline( fin, qstr );
     }
     fin.close();
   }

像这样的东西:

#include <iostream>
#include <fstream>
#include <boost/tokenizer.hpp>
#include <string>

int main() {
   using namespace std;
   using namespace boost;

   string line, file_contents;
   fstream file("test.csv");

   if (!file.is_open()) {
     cerr << "Unable to open file" << endl;
     return 1;
   }


   getline(file, line);
   tokenizer<> tok_head(line);
   int n_columns = 0;
   for (tokenizer<>::iterator beg=tok_head.begin(); beg!=tok_head.end(); ++beg) {
       cout << *beg << '\t';
       n_columns++;
   }
   cout << endl;

   while (getline(file, line)) {
     file_contents += line;
   }

   file.close();

   tokenizer<> tok(file_contents);


   int i = 0;
   for (tokenizer<>::iterator beg=tok.begin(); beg!=tok.end(); ++beg, ++i) {
       cout << *beg;
       if (i % n_columns) {
         cout << '\t';
       } else {
         cout << endl;
       }
   }

   return 0;
}

生成文件

all: t

t: csv.cpp
    g++ -I /usr/include/boost csv.cpp -o t

看起来您必须使用不同的逻辑解析每一行,因此您应该首先检查第一列并使用它应用适当的逻辑,下面是一些伪代码:

    std::fstream fs("test.txt");
    std::string line;

    //
    // Read line by line
    while (std::getline(fs, line)) {

        std::istringstream str(line);
        std::string rec_type;

        // Read record type (your first two lines looks like are of no type?)
        if ( !std::getline(str, rec_type, ',') )
            continue;

        // Decide type of record, and parse it accordingly
        if ( rec_type == "Transportation Cost") {
            std::string val;

            // Read comma delimited values
            if ( !std::getline(str, val, ',') )
                continue;
            int ival1 = std::stoi(val);

            if ( !std::getline(str, val, ',') )
                continue;
            int ival2 = std::stoi(val);
            // ...
        }

        if ( rec_type == "Tariffs") {
            std::string val;
            if ( !std::getline(str, val, ',') )
                continue;
            int ival = std::stoi(val);
            // ...
        }
    }

一种方法是将每一行视为单独的记录和对象。
让对象读取它们的数据。

例如:

class Tariff
{
  int values[3];
  public:
    friend std::istream& operator>>(std::istream& input, Tariff& t);
};

std::istream& operator>>(std::istream& input, Tariff& t)
{
  // Read and ignore the label "Tariff"
  std::string name;
  std::getline(input, name, ','); // Read until ',' delimiter.
  input >> t.value[0];
  // Note: the ',' is not a digit, so it causes an error state,
  // which must be cleared.
  input.clear();
  input >> t.value[1];
  input.clear();
  input >> t.value[2];
  input.clear();
}  

另一种方法是先读取标签,然后委托给读取行的函数。

std::string row_text;
std::getline(text_file, row_text);  // Read in first line and ignore.
while (std::getline(text_file, row_text))
{
  std::istringstream text_stream(row_text);
  std::string label;
  std::getline(text_stream, label, ','); // Parse the label.

  // Delegate based on label.
  // Note: can't use switch for strings.
  if (label == "Tariffs")
  {
      Input_Tariff_Data(text_stream);
  }
  else if (label == "ShippingType")
  {
      Input_Shipping_Type_Data(text_stream);
  }
  //...
} // End-while 

if-else梯形图可以由使用函数指针的查找表代替。 有时表格更容易阅读。

typedef void (*P_Input_Processor)(std::istringstream& text_stream);
struct Table_Entry
{
  char const * label;
  *P_Input_Processor input_processor;
};

//...
const Table_Entry delegation_table[] =
{
  {"Tariffs", Input_Tariff_Data},
  {"ShippingType", Input_Shipping_Type_Data},
};
const unsigned int entry_quantity =
    sizeof(delegation_table) / sizeof(delegation_table[0]);
// ...
std::string row_text;
std::getline(input_file, row_text); // Read and ignore first line.
while (std::getline(input_file, row_text))
{
  // Create a stream for parsing.
  std::istringstream text_stream(row_text);

  // Extract label text
  std::string label;
  std::getline(text_stream, label, ',');

  // Lookup label in table and execute associated function.
  for (unsigned int index = 0; index < entry_quantity; ++index)
  {
    if (label == delegation_table[index].name)
    {
      // Execute the associated input function
      // by derferencing the function pointer.
      delegation_table[index](text_stream);
      break;
    }
  }
}

查找表的替代方法是使用:
std::map<std::string, P_Input_Processor>
或者
std::map<std::string, void (*P_Input_Processor)(std::istringstream&)>

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

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