2016-04-21 13 views
-2

Ich habe versucht, folgende Datentabelle zu lesen und ein Objekt für die HUBs (Zeilen) und ein anderes Objekt für Kontinent (Spalten) zu erstellen. Da ich kein C++ erfahrener Benutzer bin, hatte ich einige Schwierigkeiten. Die Daten sind im Folgenden. Die Nummer nach HUB und der Bindestrich zeigt die Reihenfolge vom Hub an. Die anderen Zahlen unter jedem Kontinent sind die entsprechenden Kosten und Tarife zwischen einem HUB und einem Kontinent. Ich möchte in der Lage sein, zum Beispiel cout folgenden und das Ergebnis zu erhalten, die 73. cout << hub(1)->cont(USA)->transport() << endl;Lesen von Spalten aus einer kommagetrennten Datendatei C++

,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 

Wirklich zu schätzen Ihre Hilfe wäre. Hier ist, was ich versucht habe, so weit:

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(); 
    } 
+2

Sie können jede Zeile über 'getline' aus den' ' Header lesen. Dann können Sie jeden Zeilenstring in einen 'istringstream' platzieren und jedes Datum auch über' getline' lesen, indem Sie ein Komma als Zeilenbegrenzer angeben. Aber das ist wirklich viel zu offen: Es gibt Billionen von Möglichkeiten, dies zu tun, also zu eng zu wählen, als zu breit. –

Antwort

0

Etwas wie folgt aus:

#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; 
} 

Makefile

all: t 

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

Es sieht aus wie Sie jede Zeile unterschiedliche Logik analysieren müssen, so Sie sollten zuerst die erste Spalte überprüfen und dann die entsprechende Logik anwenden. Unten finden Sie einen Pseudocode:

0

Eine Methode besteht darin, jede Zeile als separaten Datensatz und Objekt zu betrachten.
Lassen Sie die Objekte ihre Daten lesen.

Zum Beispiel:

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(); 
} 

Eine andere Methode ist das Etikett zuerst zu lesen, dann auf eine Funktion übertragen, die in der Zeile liest.

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 

Der if-else Leiter kann durch eine Lookup-Tabelle ersetzt werden, die Funktionszeiger verwendet. Manchmal ist der Tisch leichter zu lesen.

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; 
    } 
    } 
} 

Eine Alternative zu der Lookup-Tabelle verwenden:
std::map<std::string, P_Input_Processor>
oder
std::map<std::string, void (*P_Input_Processor)(std::istringstream&)>

+0

** Downvoter **: Bitte fügen Sie einen Kommentar hinzu, der Ihren Downvote erklärt. –

+0

..Das sieht wie eine gültige Antwort, "warum downvote es ... Es würde definitiv helfen, die Antwort zu verbessern, wenn Downvoter für Kommentare beauftragt werden wird, kann SO auf diese Art von Fragen aussehen :( – Tejendra

Verwandte Themen