c++ - Asigning variables for individual elements in a row
问题描述
i'm a quite unexperienced c++ user and i've recently encountered a problem. I need to write a script that would operate on given input. Input is a coordinate file including 108 rows with 4 records in each row. First record is always a letter, specifying the element and the other three records are three numbers of equivalent length, representing x y and z components, with blank space fs, like this:
O 4.972407 6.001956 6.766559
O -1.537917 5.179561 5.602830
.....
My script should extract certain rows and print them in some output file. This i've already done using while, if and getline, like this:
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();
}
The lines extracted have to be in precise order, so i've had to include 17 of those with 17 line strings. It get pretty extensive and i'm sure there should be an easier way to do this. I would appreciate any suggestions and ideas.
Now the real problem comes when i actually get the output file. I need to assign a variable for each number in a row, in order to put them inside a formula. I tried doing this using array, like this:
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;
}
}
but i think there must be a problem with every fourth element being a letter. The output is get:
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
I'd appreciate any ideas, corrections, suggestions that would improve my script.
[edit]
About the first part. I have a coordinate file and i need to extract specific lines in sets of five, like this:
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 ....
I cannot do it using just one while cycle cause it will print out lines according to their initial position. So, likewise i wrote 17 while loops like the one i showed to print out 17 sets. Any suggestions?
Input file looks like this:
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
and on and on.
I know the atoms i need, that means i know the line i need to extract, thats all. So all i wanted to ask, is there any way to improve my script?
解决方案
关于你的第二部分:
double grades[SIZE]; ... for (int i = 0; i < SIZE; i++) { inFile >> grades[i]; cout << grades[i] << " "; }
因为
第一条记录总是一个字母
第一个inFile >> grades[i];
不会成功(像“O”这样的字母不是有效的浮点表示)并且inFiLe将出错,下一个>>
也不会做任何事情。
所以成绩没有在for中设置,你总是打印来自全局数组初始化的默认值 0。
如果你想记住双打,你还必须阅读这封信,所以要阅读一个字母(可能通过一个字符串)然后 3 double 然后再读一个字母等
我鼓励您检查每次读取是否成功以检测无效文件,包括过早的 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();
}
编译和执行(文件太短):
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 $
请注意,在您的操作方式中,您不会返回读取的双精度数,您无法将最终的 0 与初始化设置的数字区分开来。
std::vector<double>
使用 a而不是数组也更实用,避免了大小的限制,您可以从向量而不是单独获取大小。
关于问题警告的第一部分,line_no
并不表示您阅读的行的排名,因为每次if之一为真时,您都会在没有更新的情况下阅读一行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();
}
但是因为你要写的第二行是
O -3.375664 6.157090 4.244211
所以你的代码中的 59 是错误的,我的建议中的第二个数字必须替换为 39(预期的行是第 39 行编号第一行 1)
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
也许62, 90, 106
也是错误的,但是您提供的集合不包含第三行的预期行,因此我无法检查/更正
推荐阅读
- amazon-web-services - 在 AWS EMR 中提交 Spark 作业
- json - 聚合相似的对象对字段求和
- javascript - 如何在 react admin v3 中设置时区?
- swift - 为什么不能在 Swift 中从 Facebook Graph API 下载图像?
- command-line - wget 和外部图像的问题
- javascript - 使用 javascript 检测用户的区域设置是否设置为 12 小时或 24 小时时间格式
- ruby-on-rails - 更改表单提交时的 URL 参数
- java - 如何创建可在整个应用程序中访问但同时请求特定的变量?
- laravel - 从 laravel 调用 HTTPS 请求到外部 API
- ruby-on-rails - ActiveAdmin 预编译资产