2012-03-13 2 views
1

Структура довольно проста:Как читать список с подписок из файла?

  1. Главная точка
    1. Элемент списка - 5
    2. Элемент списка - 6
    3. ...
  2. Главная точка
    1. Список - 2
    2. Элемент списка - 3
    3. ...

Для того, чтобы было легче читать, я добавил некоторые разделители, Вот сам файл:

>Point one 
item 1  | 150 
item 2  | 20 
>Point two 
item 1  | 150 
item 2  | 10 

И я написал функцию C++ который должен его прочитать. Но я запутался где-то в своей собственной логике и допустил ошибку. Может ли это найти для меня?

ifstream fileR("file.txt"); 

    int i = 0; 
    getline(fileR, sTemp); 
    do { 
    if(!sTemp.empty() && sTemp[0]==DELIM){ 
     R[0][i] = sTemp.substr(1); 
     i++; 
    }else{ 
     j = 0; 
     do { 
      if(!sTemp.empty() && sTemp[0] != DELIM){ 
       string::const_iterator pos = find(sTemp.begin(), sTemp.end(), '|'); 
       string name(sTemp.begin(), pos); 
       string a_raw(pos + 1, sTemp.end()); 
       a_raw = trim(a_raw); 
       double amount(atof(a_raw.c_str())); 
       R[j+1][i].set(trim(name), amount); 
       j++; 
      }else{ 
       break; 
      } 
     }while(getline(fileR, sTemp)); 
    } 
    }while(getline(fileR, sTemp)); 

Где значения чтений передаются не важен, потому что я попытался упростить эту функцию, потому что это на самом деле некоторые контейнеры с динамическими массивами. Я тестировал их, и они отлично работают. Таким образом, есть проблема с чтением. Это шов, чтобы прочитать первое значение штрафа, но потом он делает какой-то беспорядок.
Если вы считаете, что моя попытка - полная катастрофа, я бы приветствовал намеки на то, как сделать действительно действующую функцию.

EDIT:
У меня хороший сон ночью, и я исправил его. Вот версия wokrking:

bool read = true; 
    for(int i = 0; i<n; i++) { 
    if(read){getline(fileR, sTemp);}else{ read = true; } 
    if(!sTemp.empty() && sTemp[0]==DELIM){ 
     R[i].setName(sTemp.substr(1)); 
     i--; 
    }else{ 
     R[i].toFirstSubpoint(); 
     do { 
      if(!sTemp.empty() && sTemp[0] != DELIM){ 
       string::const_iterator pos = find(sTemp.begin(), sTemp.end(), '|'); 
       string name(sTemp.begin(), pos); 
       string a_raw(pos + 1, sTemp.end()); 
       a_raw = trim(a_raw); 
       double amount(atof(a_raw.c_str())); 
       R[i].setSubpoint(trim(name), amount); 
       R[i].toNextSubpoint(); 
      }else{ 
       read = false; 
       break; 
      } 
     }while(getline(fileR, sTemp)); 
    } 

моя самая главная ошибка в том, что я забыл, что, если после того, как условие проверяется цикл переходит к следующему индексу и не выполняет другие (еще) состояние этого.

Ответ ниже на самом деле лучший способ сделать это гораздо проще и понятнее, но я не мог использовать векторы на этот раз, и я предполагаю, что мой скрипт должен быть немного быстрее, поскольку он не использует их. Так или иначе, в следующий раз, когда я столкнусь с подобной ситуацией, я воспользуюсь решением ниже.

ответ

2

Вы, вероятно, следует рассмотреть возможность использования библиотеки синтаксического анализа, как повышение :: дух, однако, если формат файла не является обязательным Есть много, что вы можете сделать, чтобы сделать его легче разобрать без применения таких мер,

Рассмотрим следующий пример date layout

MainPoint1 iname1 ivalue1 iname2 ivalue2 iname3 ivalue3 
MainPoint2 iname1 ivalue1 iname2 ivalue2 

Это может быть легко загружено следующим.

struct item{ 
    std::string name; 
    double value; 
}; 

std::ostream& operator<<(std::ostream& os, const item& i) 
{ 
    return os << i.name << " " << i.value; 
} 

std::istream& operator>>(std::istream& is, const item& i) 
{ 
    return is >> i.name >> i.value; 
} 

struct point{ 
    std::string value; 
    std::vector<item> items; 
}; 


std::istream& operator>>(std::istream& is, point& p) 
{ 
    std::string line; 
    std::getline(is, line); 
    std::stringstream ss(line); 
    ss >> p.value; 
    p.assign(
     std::istream_iterator<item>(ss), 
     std::istream_iterator<item>()); 
    return is; 
} 


std::ostream& operator<<(std::istream& os, const point& p) 
{ 
    os << p.value << " "; 
    std::copy(p.item.begin(), p.items.end(), 
     std::ostream_iterator<item>(os, " "), 
    return os; 
} 

int main() 
{ 
    /* 
    ** Deserailise 
    */ 
    std::ifstream in_file("infile.dat"); 
    std::vector<point> points(
     std::istream_iterator<point>(in_file), 
     std::istream_iterator<point>()); 


    /* 
    ** Serailise 
    */ 
    std::ofstream out_file("outfile.dat"); 
    std::copy(points.begin(), points.end() 
     std::ostream_iterator<points>(out_file, "\n")); 
} 

Это целая непроверенная и несвязанная, но концептуально она должна работать.

EDIT: код изменен для соответствия изделию с именем и стоимостью.

+0

Благодарим за отзыв, но каждый предмет подписок состоит из двух значений: имя и двойная переменная. – Povylas

+0

@Povylas просто применяют то, что я показал вам рекурсивно, вместо того, чтобы элемент std :: string создавал свою собственную структуру с помощью собственного op <<. Я попробую и продемонстрирую, что сейчас – 111111

+0

@ Повилась, пожалуйста, посмотрите, пожалуйста, код. – 111111

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