我是一位经验不足的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
等等。
我知道我需要的原子,这意味着我知道我需要提取的线,仅此而已。所以我想问的是,有什么办法可以改善我的脚本?
答案 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
也是错误的,但是您给出的集合中没有包含第三行中的预期行,因此我无法检查/更正