0

私はファイルを持っています:

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 座標が続きます。私が認識しなければならない「T」に到達するまで、数字は変化します。次に、「r」、「s」、または「t」の後にいくつかの値が続く可能性があります。

とにかく、「P」を認識して2つのフロートを取り込む方法は知っていますが、「T」に到達すると停止するX座標とY座標のwhileループが必要であることはわかっています。ループを停止して「T」を認識してから別のことを行うには、C++ について十分に知りません。

説明する例をいただければ幸いです。前もって感謝します!

4

4 に答える 4

9

これを行うための適切なC++の方法であると私が思うことをお見せします。最初に、最初の行を表し、そのIOを実行するためのクラスを定義します。

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

真ん中の線があるセクションの終わりに達すると、「T」に遭遇することになっています。その場合、ストリームの失敗ビットを上げます。これにより、読み取る中間行がもうないことがクライアントに通知されます。

最後に、最後の行のクラス:

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

それぞれにいくつの値があるかわからないため、最後の行はより複雑です。そのため、できるだけ多くの値を読み取るだけです。

それはトリッキーな部分でした。これで、メイン関数は最初の1行、次に不明な数の中間行、最後に不明な数の最後の行を読み取るだけです。

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

データのソースとして文字列を使用しましたが、おそらくファイルから読み取りたいと思うでしょう。

これで、ループを1つも作成しなかったことがわかります。

これがコードパッドのコードです。

于 2010-02-22T10:21:25.143 に答える
0
  • 一種の「グローバル状態」を維持する
  • ファイルの終わりまでファイルから行を読み取るループを作成します。
  • 行をバッファに読み込む
  • バッファの最初の文字をチェックし、それが P または T または r または s または t の場合、アプリケーションのグローバル状態を変更します
  • 最初の文字が T の場合、sscanf(Buffer+1,"%lf %lf %lf",&first,&second,&third) を使用して行の残りを読み取ります。
  • 最初の文字が r、s、または t の場合、同様のことを行います。
  • アプリケーションが「P-state」にある場合は、sscanf(Buffer,"%lf %lf",&first,&second) を使用してバッファをスキャンするだけです
于 2010-02-22T07:45:33.647 に答える
0


標準ストリームを使用して「P」と「T」をチェックできると思います
get(char &ch); を使用します。
putback(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;  
}
于 2010-02-22T07:54:22.633 に答える
0

ユーザーはテキスト ファイルを 1 行ずつ読み取り、文字列 word を実行します。

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());
     }
    }
}
于 2010-02-22T08:02:31.870 に答える