Простой ввод C ++ из файла ... как? - PullRequest
0 голосов
/ 22 февраля 2010

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

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 ]

9 голосов
/ 22 февраля 2010

Я покажу вам, что я думаю, что это правильный 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

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

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

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

0 голосов
/ 22 февраля 2010

Я думаю, вы можете использовать стандартные потоки
проверить "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;  
}
0 голосов
/ 22 февраля 2010

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

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());
     }
    }
}
0 голосов
/ 22 февраля 2010
  • Сохраняйте своего рода «глобальное состояние»
  • Написать цикл, который читает строку из файла до конца файла.
  • Считать строку в буфер
  • Проверьте первый символ буфера, если это 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)
...