Как прочитать список с подсписками из файла? - PullRequest
1 голос
/ 14 марта 2012

Структура довольно проста:

  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:
У меня хороший ночной сон, и я исправил это. Вот вариант работы:

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

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

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

1 Ответ

2 голосов
/ 14 марта 2012

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

Учитывайтеследующий макет даты

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

Это непроверенный и не скомпилированный, но концептуально это должно работать.

РЕДАКТИРОВАТЬ: код изменен для соответствия элементу с именем и значением.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...