Простой ввод C++ из файла... как?

У меня есть файл:

P 0.5 0.6 0.3
30 300
80 150
160 400
200 150
250 300
T
r  45 0 0
s 0.5 1.5 0 0
t 200 –150
.
.
.

Когда я читаю в "P", я знаю, что последуют 3 поплавка. За этим последует конечное число координат X и Y. Число будет меняться до тех пор, пока не будет достигнут знак "Т", который я должен распознать. Тогда может быть 'r', 's' или 't', за которыми следуют некоторые значения.

В любом случае я знаю, как распознать 'P', а затем взять 2 числа с плавающей точкой, но потом я знаю, что должен иметь цикл while для координат X и Y, который остановится, когда я доберусь до 'T'. Я не знаю достаточно о C++, чтобы остановить цикл и распознать 'T', а затем сделать что-то еще.

Пример для объяснения будет принята с благодарностью. Заранее спасибо!

4 ответа

Решение

Я покажу вам, что я думаю, это правильный C++ способ сделать это. Сначала определите класс для представления вашей первой строки и для выполнения ее ввода-вывода:

struct FirstLine
{
    double x, y, z;
    friend std::istream & operator>>(std::istream & is, FirstLine & data)
    {
        std::string line, ignore;
        std::getline(is, line);
        std::istringstream iss(line);
        iss >> ignore >> data.x >> data.y >> data.z;
        assert(ignore == "P" && iss);
        return is;
    }
    friend std::ostream & operator<<(std::ostream & os, FirstLine const & data)
    {
        return os << "P " << data.x << " " << data.y << " " << data.z;
    }    
};

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

Теперь класс для средних линий:

struct MiddleLine
{
    double x, y;
    friend std::istream & operator>>(std::istream & is, MiddleLine & data)
    {
        std::string line;
        std::getline(is, line);
        if(line == "T")
            is.clear(std::ios::failbit);
        else
        {
            int n = sscanf(line.c_str(), "%lf %lf", &data.x, &data.y);
            assert(n == 2);
        }
        return is;
    }
    friend std::ostream & operator<<(std::ostream & os, MiddleLine const & data)
    {
        return os << data.x << " " << data.y;
    }    
};

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

Наконец класс для последних строк:

struct LastLine
{
    std::string identifier; // r, s or t
    std::vector<double> values;
    friend std::istream & operator>>(std::istream & is, LastLine & data)
    {
        std::string line;
        std::getline(is, line);
        std::istringstream iss(line);
        iss >> data.identifier;
        assert(data.identifier == "r" || data.identifier == "s" 
               || data.identifier == "t");
        std::copy(std::istream_iterator<double>(iss), 
                  std::istream_iterator<double>(), std::back_inserter(data.values));
        return is;
    }
    friend std::ostream & operator<<(std::ostream & os, LastLine const & data)
    {
        os << data.identifier << " ";
        std::copy(data.values.begin(), data.values.end(),
                  std::ostream_iterator<double>(os, " "));
        return os;
    }      
};

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

Это была сложная часть. Теперь наша основная функция будет просто читать одну первую строку, затем неизвестное количество средних строк и, наконец, неизвестное количество последних строк:

int main()
{
    std::string const data = "P 0.5 0.6 0.3\n
                             "30 300\n"
                             "80 150\n"
                             "160 400\n"
                             "200 150\n"
                             "250 300\n"
                             "T\n"
                             "r  45 0 0\n"
                             "s 0.5 1.5 0 0\n"
                             "t 200 –150";

    std::istringstream iss(data);

    FirstLine first_line;
    iss >> first_line;

    std::vector<MiddleLine> middle_lines;
    std::copy(std::istream_iterator<MiddleLine>(iss), 
              std::istream_iterator<MiddleLine>(), 
              std::back_inserter(middle_lines));
    iss.clear();

    std::vector<LastLine> last_lines;
    std::copy(std::istream_iterator<LastLine>(iss), 
              std::istream_iterator<LastLine>(), 
              std::back_inserter(last_lines));
    assert(iss.eof());       

    std::cout << first_line << "\n";
    std::copy(middle_lines.begin(), middle_lines.end(),
              std::ostream_iterator<MiddleLine>(std::cout, "\n"));
    std::copy(last_lines.begin(), last_lines.end(),
              std::ostream_iterator<LastLine>(std::cout, "\n"));
    return 0;
}

Это результат, который вы получите:

P 0.5 0.6 0.3
30 300
80 150
160 400
200 150
250 300
r 45 0 0
s 45 0 0 0.5 1.5 0 0
t 45 0 0 0.5 1.5 0 0 200

Я использовал строку в качестве источника моих данных, но вы, вероятно, захотите прочитать из файла.

И это все, вы можете видеть, что я не написал ни одного цикла.

Вот код в кодовой панели.

Пользователь читает текстовый файл построчно, а затем запускает строковое слово;

ifstream fin(your file)
while(! fin.eof())
{
    string line = fin.getline();
    istringstream iss(line, istringstream::in);
    string token;
    while( iss >> token)     
    {
      if (token.compare("T")) {
        ...
      } else {
        float f = atof(token.c_str());
     }
    }
}

Я думаю, что вы можете использовать стандартные потоки
проверить "P" и "T"
используйте get(char &ch);
и отложите (ch), чтобы вернуть его в поток
а также
yourstream >> x >> y >> endl;

http://www.cplusplus.com/reference/iostream/istream/putback/

// Example
// istream putback
#include <iostream>
using namespace std;

int main () {  
  char c;  
  int n;  
  char str[256];  

  cout << "Enter a number or a word: ";
  c = cin.get();  

  if ( (c >= '0') && (c <= '9') )
  {  
    cin.putback (c);
    cin >> n;
    cout << "You have entered number " << n << endl;
  }  
  else
  {  
    cin.putback (c);
    cin >> str;
    cout << " You have entered word " << str << endl;
  }  

  return 0;  
}
  • Держите своего рода "глобальное государство"
  • Напишите цикл, который читает строку из файла до конца файла.
  • Прочитать строку в буфер
  • Проверьте первый символ буфера, если это P или T или r или s или t, измените глобальное состояние приложения
  • Если первый символ был буквой T, используйте sscanf(Buffer+1,"%lf %lf %lf",&first,&second, third), чтобы прочитать оставшуюся часть строки.
  • Сделайте что-то подобное, если первый символ - это r, s или t.
  • Если приложение находится в "P-состоянии", просто просканируйте буфер с помощью sscanf(Buffer,"%lf %lf",&first,&second)
Другие вопросы по тегам