2013-11-18 4 views
0

Здравствуйте, у меня возникли проблемы с получением моих значений для правильного чтения из CSV-файла. Я хочу заполнить вектор 1000 объектами, определенными пользователем (DetectedParticle), с их переменными, назначенными из файла. Объект имеет 4 члена переменных (x0, x1, x2, x3) типа double. В файле каждая строка должна соответствовать одной записи в векторе, и каждый столбец строки должен быть прочитан в свою соответствующую переменную в объекте.чтение дубликатов из CSV-файла в C++

формат файла, как это (за исключением комментариев):

wordswordswordswordswords 
2.231,23.52,123.4,213.2 //first object to be created with these values 
23213,23123,41234,45236 //second 
21323,123123,123123,2435 //third 
. 
. 
. 
23434,234234,234234,234 //1000th 

Проблема заключается в том, что читает только в любой другой линии в векторе. Таким образом, вектор будет иметь объект из первой строки после слов, а затем он будет иметь третью строку, но он пропустит вторую строку. В результате у меня есть вектор размером 499, а не размер 1000. Он успешно присваивает столбцу правильной переменной-члену, хотя он просто не делает этого достаточно времени! Вот фрагмент кода:

std::vector<DetectedParticle> populate(std::string file){ //DetectedParticle is my user defined type with membervariables x0,x1,x2,x3 
std::vector<DetectedParticle> temp; //creates a vector of Detected Particles for later returning 
std::ifstream fin("detectedpositrons.csv"); //ifstream to read from 
std::string linestr;  //string for the stream to be read into    

if (!fin.is_open()) { std::cerr << "failed to open file\n"; } // check file is open, error message if not 

fin.ignore (std::numeric_limits<std::streamsize>::max(), '\n'); //ignores first 


while (std::getline(fin, linestr)){  // 
    int i = 0; 
    DetectedParticle temppart; 

while (std::getline(fin,linestr,',')) 
{ 
    if (i == 4){temp.push_back(temppart); break;} //when it gets to teh end of the line, past the 4th column, it breaks and should go to the next line 
    float holder ;            //float for the string to be held in 
    std::istringstream(linestr) >> holder;   //converts string to float 
    if(i == 0){ temppart.x0 = holder; i++;}   //if first column, sets x0 equal to the value 
    else if (i == 1){ temppart.x1 = holder; i++;} //if second column, sets x1 = to value 
    else if (i == 2){ temppart.x2 = holder; i++;} //if 3rd column sets x2= value 
    else if (i == 3){ temppart.x3 = holder; i++;} //if last column it populates the last value x3 with that value. 

} 
} 
return temp; //returns the populated vector 
} 

Извините, если это не так легко следовать или самый интуитивный способ для чтения файла CSV или самый хороший метод глядя, но я придумал это сам, так что следовало ожидать! Заранее спасибо!

+2

Отступа вашего кода правильно увеличивает ваши шансы получить помощь. –

+0

@ n.m .: действительно, это в ужасном формате. :-) – lpapp

+1

Я стараюсь изо всех сил; _; – rooms

ответ

0

Вы отбрасываете линию, у которой у вас есть внешний контур (while (std::getline(fin, linestr)){). Вы злоупотребляете getline, чтобы нарезать входные данные в составные части - это набухание, но вы не используете линию, которую вы уже прочитали.

Если вы настаиваете на этом трюке вам нужно создать поток временной строки, которая принимает строку, вы читать во внешнем контуре, а затем запустить getline во внутреннем цикле на этом временном потоке строки, не на fin.

0

Использование Boost Spirit.

Вот пример, который вы можете адаптировать. Это делает синтаксический анализ входной строки ищет 4 разделенные запятой двойные значения и заселить std::vector из std::tuple<double, double, double, double>: например

#include <boost/spirit/include/qi.hpp> 
#include <boost/spirit/home/phoenix/object/construct.hpp> 
#include <boost/spirit/home/phoenix/container.hpp> 
#include <boost/spirit/include/phoenix_core.hpp> 
#include <iostream> 
#include <string> 
#include <tuple> 

typedef std::tuple<double, double, double, double> particle; 
typedef std::vector<particle> Particles; 

template <typename Iterator> 
bool populate_vector(Iterator first, Iterator last, Particles& vector) 
{ 
    namespace qi = boost::spirit::qi; 
    namespace ascii = boost::spirit::ascii; 
    namespace phoenix = boost::phoenix; 

    bool r = qi::phrase_parse(first, last, 
     (
      (qi::double_ >> ',' >> qi::double_>> ',' >> qi::double_ >> ',' >> qi::double_) 
      [ 
       phoenix::push_back(phoenix::ref(vector), 
        phoenix::construct<particle>(qi::_1, qi::_2 , qi::_3, qi::_4)) 
      ] 
     ), qi::space); 

    return r; 
} 

int main() 
{ 
    std::string str; 
    Particles particles; 

    while (getline(std::cin, str)) 
    { 
     if (str.empty() || str[0] == 'q' || str[0] == 'Q') 
     { 
      break; 
     } 

     if (populate_vector(str.begin(), str.end(), particles)) 
     { 
      std::cout << "Parsing succeeded: " << particles.size() << std::endl; 
     } 
     else 
     { 
      std::cout << "Parsing failed." << std::endl; 
     } 
    } 

    return 0; 
} 

Взаимодействие:

1.26,1.23,1.6,152 
Parsing succeeded: 1 
1,2,3,4 
Parsing succeeded: 2 
1

Проблема вы читаете строку, ничего не делать с ним, а затем прочитать следующую строку, чтобы разобрать:

while (std::getline(fin, linestr)) // first read 
{ 
    ... 
    while (std::getline(fin,linestr,',')) // second read 
    { 
     // you are doing stuff here 
    } 
} 

Я думаю, что вы хотите просто выбросить строку заголовка (на основании вашего описания), так что вы Shou л.д. имеет один std::getline вызова вне цикла, а затем петельные std::getline вызова для чтения в двойных значениях:

std::getline(fin, linestr); // header row - throw away 
while (std::getline(fin, linestr)) 
{ 
    istringstream iss(linestr); 
    // parse the stringstream into your vectors - I wouldn't use getline here, but you could 
} 
+0

Спасибо, помощник. Очень признателен! – rooms

Смежные вопросы