我写这个用解析带有数字的文件,其中分隔符只是一个空格。我的目标是读取文件的每个数字并将其存储在矩阵A
的相应索引中。因此,读取的第一个数字应该转到A[0][0]
,第二个数字转到A[0][1]
,依此类推。
#include <iostream>
#include <string>
#include <fstream>
using namespace std;
int main() {
const int N = 5, M = 5;
double A[N*M];
string fname("test_problem.txt");
ifstream file(fname.c_str());
for (int r = 0; r < N; ++r) {
for (int c = 0; c < M; ++c) {
file >> *(A + N*c + r);
}
}
for (int r = 0; r < N; ++r) {
for (int c = 0; c < M; ++c) {
cout << *(A + N*c + r) << " ";
}
cout << "\n";
}
cout << endl;
return 0;
}
现在,我正在尝试解析这样的文件:
1 ;2 ;3 ;4 ;5
10 ;20 ;30 ;40 ;50
0.1 ;0.2 ;0.3 ;0.4 ;0.5
11 ;21 ;31 ;41 ;5
1 ;2 ;3 ;4 ;534
但它会打印(因此读取)垃圾。我该怎么办?
修改
这是我在C中的尝试,也失败了:
FILE* fp = fopen("test_problem.txt", "r");
double v = -1.0;
while (fscanf(fp, "%f ;", &v) == 1) {
std::cout << v << std::endl;
}
-1将始终打印。
答案 0 :(得分:2)
C示例的问题:
warning: format ‘%f’ expects argument of type ‘float*’, but
argument 3 has type ‘double*’ [-Wformat=]
随时随地打开警告(-Wall -Wextra
)并进行更多错误检查。
无论如何,要fscanf
进入double
,您需要%lf
代替%f
。
答案 1 :(得分:2)
根据您的输入格式......
1 ;2 ;3 ;4 ;5
......你的代码......
for (int c = 0; c < M; ++c) {
file >> *(A + N*c + r);
}
...将&#34;吃&#34;第一个数值,然后在第一个;
分隔符上阻塞。最简单的修正是......
char expected_semicolon;
for (int c = 0; c < M; ++c) {
if (c) {
file >> expected_semicolon;
assert(expected_semicolon == ';'); // if care + #include <cassert>
}
file >> *(A + N*c + r);
}
无论价值多少,要添加更好的错误检查,我建议......
if (std::ifstream file(fname))
{
...use file stream...
}
else
{
std::cerr << "oops\n";
throw or exit(1);
}
...作为打开文件流的一般做法。
对于循环获取数据,使用支持宏来提供类似断言的样式适用于流:
#define CHECK(CONDITION, MESSAGE) \
do { \
if (!(CONDITION)) { \
std::ostringstream oss; \
oss << __FILE__ << ':' << __LINE __ \
<< " CHECK FAILED: " << #CONDITION \
<< "; " << MESSAGE; \
throw std::runtime_error(oss.str()); \
} while (false)
...
for (int c = 0; c < M; ++c) {
if (c)
CHECK(file >> expected_semicolon &&
expected_semicolon == ';',
"values should be separated by semicolons");
CHECK(file >> *(A + N*c + r), "expected a numeric value");
}
对于这种特定的输入解析,对于生产系统,您可能希望使用getline
,这样您就可以知道您在输入中的位置......
size_t lineNum = 0;
std::string my_string;
for (int r = 0; r < N; ++r) {
CHECK(getline(file, my_string), "unexpect EOF in input");
++lineNum;
std::istringstream iss(my_string);
for (int c = 0; c < M; ++c) {
if (c)
CHECK(file >> expected_semicolon &&
expected_semicolon == ';',
"unexpected char '" << c
<< "' when semicolon separator needed on line "
<< lineNum);
CHECK(iss >> *(A + N*c + r),
"non numeric value encountered on line " << lineNum);
}
}
}
答案 2 :(得分:1)
转换前应删除分号
std::string temp;
file >> temp;
std::replace( temp.begin(), temp.end(), ';', ' ');
*(A + N*c + r) = std::stod( temp );
答案 3 :(得分:0)
为什么不尝试使用getline(),它接受Delimiter作为第三个参数。
string buffer;
for (int c = 0; c < M; ++c) {
getline(file, buffer, ';');
stringstream tmp(buffer);
tmp>>*(A + N*c + r);
}
getline()将读取,直到下一个分隔符或换行符或文件结尾