连续为各个元素分配变量

时间:2019-05-23 12:10:15

标签: c++

我是一位经验不足的C ++用户,最近遇到了一个问题。我需要编写一个可以在给定输入下运行的脚本。输入是一个坐标文件,包括108行,每行4条记录。第一个记录始终是字母,指定元素,其他三个记录是三个等长长度的数字,代表x y和z分量,并带有空格fs,如下所示:

O      4.972407     6.001956     6.766559
O     -1.537917     5.179561     5.602830
.....

我的脚本应提取某些行并将其打印在某些输出文件中。我已经使用while,if和getline完成此操作,如下所示:

if (myfile.is_open())
{
   int line_no = 1;  
   while (line_no <= 108 && getline(myfile,line)) {
     line_no++;  
     if (line_no == 19) {
       getline (myfile,line);  
       cout << line << '\n';  
     }
     else if (line_no == 59) {
      getline (myfile,line);  
      cout << line << '\n';  
     }
     else if (line_no == 60) {
      getline (myfile,line);  
      cout << line << '\n';  
     }
     else if (line_no == 87) {
       getline (myfile,line);  
       cout << line << '\n';  
     }
     else if (line_no == 102) {  
       getline (myfile,line);  
       cout << line << '\n';   
     }
  }
  myfile.close();
}

提取的行必须具有精确的顺序,因此我必须包括17个带有17个行字符串的行。它变得相当广泛,我敢肯定应该有一个更简单的方法来做到这一点。我将不胜感激任何建议和想法。

现在真正的问题出在我实际获取输出文件时。我需要为行中的每个数字分配一个变量,以便将其放入公式中。我尝试使用数组来执行此操作,如下所示:

const int SIZE = 60;  
double grades[SIZE];  

void readData() {
  string inFileName = "out.txt";  
  ifstream inFile;   
  inFile.open(inFileName.c_str());  

  if (inFile.is_open())
  {   
     for (int i = 0; i < SIZE; i++)  
     {  
        inFile >> grades[i];  
        cout << grades[i] << " ";  
     }  

     inFile.close(); // CLose input file  
  }  
  else { //Error message   
    cerr << "Can't find input file " << inFileName << endl;  
  }
}  

但是我认为每四个元素都是一个字母肯定有问题。输出为:

0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0

我会感谢任何可以改善我的脚本的想法,更正和建议。


[编辑]

关于第一部分。我有一个坐标文件,我需要以五组为一组提取特定的行,如下所示:

P     -3.070974     5.319084     5.505385   
O     -3.375664     6.157090     4.244211  
O      4.972407     6.001956     6.766559  
O     -1.537917     5.179561     5.602830   
O      4.900104     3.921648     5.407940  
P      3.070979     4.630705     1.835121   
O      3.644369     3.947834     0.573947 ....

我不能仅用一个循环来完成它,因为它将根据其初始位置打印出行。因此,同样,我写了17个while循环,就像我展示的那样打印出17套。有什么建议吗?

输入文件如下:

P      6.783213     2.487446     1.835121   
P     -2.474827     4.974898    20.186419  
P      2.474819     4.974898     9.175649   
P      1.237407     7.118158    20.186419  
P     -1.237416     2.831639     9.175649  
P      1.237407     2.831639    20.186419   
P     -1.237416     7.118158     9.175649   
P      5.545802     0.344186    12.845891    
P      5.545802     4.630705    12.845891   
P      1.833567     2.487446    12.845891    
P      2.474823     0.000000    16.516155    
P      3.070974     5.319084    16.516155   
P     -1.237412     2.143260    16.516155     
O     -0.664021     1.460388    15.254981   
O      4.972412     1.027057    14.107065    
O      3.375664     6.157090    15.254981     
O      5.241113     3.792699    14.107065     
O     -2.711642     7.307209    15.254981     
O      2.711646     2.642580    14.107065    
O      1.596740     5.130033    10.436823     
O     -1.596748     4.819764    18.925245     
O     -0.664026     3.514510    10.436823     
O      0.664017     6.435287    18.925245      

等等。

我知道我需要的原子,这意味着我知道我需要提取的线,仅此而已。所以我想问的是,有什么办法可以改善我的脚本?

1 个答案:

答案 0 :(得分:0)

关于第二部分:

 double grades[SIZE];  
 ...
 for (int i = 0; i < SIZE; i++)  
 {  
     inFile >> grades[i];  
     cout << grades[i] << " ";  
 }  

因为

  

第一个记录始终是字母

第一个inFile >> grades[i];不会成功(像'O'这样的字母不是有效的浮点表示),并且 inFiLe 将出错,并且下一个{{1} }也会有所作为。

因此在 for 中未设置 grades ,并且您始终打印来自全局数组初始化的默认值0。

如果您想记住双打,还必须阅读字母,因此要读一个字母(可能是通过字符串),则先三遍再读一个字母,等等。

我建议您检查每次读取是否成功以检测到无效文件,包括过早的EOF

例如:

>>

编译和执行(文件太短):

#include <iostream>
#include <fstream>

using namespace std;

const int SIZE = 60;  
double grades[SIZE];  

void readData() {
  string inFileName = "out.txt";  
  ifstream inFile;   
  inFile.open(inFileName.c_str());  // only old C++ version does not accept std::string and required the c_str

  if (inFile.is_open())
  {   
    string s; // to read 2 letters like Ti in your input after edition

    for (int i = 0; i < SIZE; i++)  
    {  
      if ((i % 3) == 0) {
        if (! (inFile >> s)) {
          cerr << endl << "error when reading letter(s) line " << (i/3)+1 << endl;
          return;
        }
      }

      if (! (inFile >> grades[i])) {
        cerr << endl << "error when reading the " << i+1 << " nth double" << endl;
        return;
      }
      cout << grades[i] << " ";  
    }  

    cout << endl;

    inFile.close(); // CLose input file  
  }  
  else { //Error message   
    cerr << "Can't find input file " << inFileName << endl;  
  }  
}

int main()
{
  readData();
}

请注意,您执行的操作不会返回读取的double数,因此无法将最后的0与初始化设置的数字区分开。

使用pi@raspberrypi:/tmp $ g++ -Wall -Wextra -pedantic v.cc pi@raspberrypi:/tmp $ cat out.txt O 4.972407 6.001956 6.766559 O -1.537917 5.179561 5.602830 pi@raspberrypi:/tmp $ ./a.out 4.97241 6.00196 6.76656 -1.53792 5.17956 5.60283 error when reading letter line 3 pi@raspberrypi:/tmp $ 而不是数组也更加实用,这样可以避免大小限制,并且可以从向量而不是单独获取大小。


关于问题警告std::vector<double>的第一部分,不是不会指出您所读行的排名,因为每次 if 都为真时,您读取一行而不更新line_no

根据您的其他信息:

  

我知道我需要的原子,这意味着我知道我需要提取的线,仅此而已。所以我想问的是,有什么办法可以改善我的脚本?

您的代码等效于该代码,更清晰,更小:

line_no

但是因为您要写的第二行是

if (myfile.is_open())
{
   static const int lineToWrite[] = { 19, 60, 62, 90, 106, -1 };
   const int * p = lineToWrite;
   int line_no = 0;  

   while (line_no <= 108 && getline(myfile,line)) {
     if (++line_no == *p) {
       cout << line << '\n';  
       p += 1;
     }
  }
  myfile.close();
}

所以您代码中的59是错误的,因此我的提案中的第二个数字必须替换为39(预期的行是第39nth表示第一行1)

O     -3.375664     6.157090     4.244211  

这样写行

if (myfile.is_open())
{
   static const int lineToWrite[] = { 19, 39, 62, 90, 106, -1 };
   const int * p = lineToWrite;
   int line_no = 0;  

   while (line_no <= 108 && getline(myfile,line)) {
     if (++line_no == *p) {
       cout << line << '\n';  
       p += 1;
     }
  }
  myfile.close();
}

也许P -3.070974 5.319084 5.505385 O 3.375664 6.157090 15.254981 也是错误的,但是您给出的集合中没有包含第三行中的预期行,因此我无法检查/更正