C++ 读取带有空格和分号分隔符的文件

C++ 读取带有空格和分号分隔符的文件,c++,file,fstream,text-parsing,C++,File,Fstream,Text Parsing,我写这篇文章是为了解析一个带有数字的文件,其中分隔符只是一个空格。我的目标是读取文件的每个编号,并将其存储在矩阵A的相应索引中。因此,读取的第一个数字应该转到A[0][0],第二个数字应该转到A[0][1],依此类推 #include <iostream> #include <string> #include <fstream> using namespace std; int main() { const int N = 5, M = 5;

我写这篇文章是为了解析一个带有数字的文件,其中分隔符只是一个空格。我的目标是读取文件的每个编号,并将其存储在矩阵
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;
}
但它会打印(从而读取)垃圾。我该怎么办


编辑

下面是我在C中的尝试,但也失败了:

FILE* fp = fopen("test_problem.txt", "r");
double v = -1.0;
while (fscanf(fp, "%f ;", &v) == 1) {
    std::cout << v << std::endl;
}
FILE*fp=fopen(“test_problem.txt”、“r”);
双v=-1.0;
而(fscanf(fp,“%f;”,&v)==1){

std::cout在转换之前应该删除分号

std::string temp;
file >> temp;
std::replace( temp.begin(), temp.end(), ';', ' ');
*(A + N*c + r) =    std::stod( temp );

转换前应删除分号

std::string temp;
file >> temp;
std::replace( temp.begin(), temp.end(), ';', ' ');
*(A + N*c + r) =    std::stod( temp );

您的C示例的问题是:

warning: format ‘%f’ expects argument of type ‘float*’, but
         argument 3 has type ‘double*’ [-Wformat=]
无论何时何地,都要打开警告(
-Wall-Wextra
)并进行更多的错误检查


无论如何,要将
fscanf
转换为
double
,您需要
%lf
而不是
%f
C示例的问题:

warning: format ‘%f’ expects argument of type ‘float*’, but
         argument 3 has type ‘double*’ [-Wformat=]
无论何时何地,都要打开警告(
-Wall-Wextra
)并进行更多的错误检查


无论如何,要将
fscanf
转换为
double
,您需要
%lf
,而不是
%f
,给定您的输入格式

1 ;2 ;3 ;4 ;5
…你的代码

for (int c = 0; c < M; ++c) {
    file >> *(A + N*c + r);
}

无论如何,为了增加更好的错误检查,我建议

if (std::ifstream file(fname))
{
    ...use file stream...
}
else
{
    std::cerr << "oops\n";
    throw or exit(1);
}

给定您的输入格式

1 ;2 ;3 ;4 ;5
…你的代码

for (int c = 0; c < M; ++c) {
    file >> *(A + N*c + r);
}

无论如何,为了增加更好的错误检查,我建议

if (std::ifstream file(fname))
{
    ...use file stream...
}
else
{
    std::cerr << "oops\n";
    throw or exit(1);
}
为什么不试试getline(),它接受分隔符作为第三个参数

string buffer;
for (int c = 0; c < M; ++c) {
    getline(file, buffer, ';');
    stringstream tmp(buffer);
    tmp>>*(A + N*c + r);
}
字符串缓冲区;
对于(int c=0;c>*(A+N*c+r);
}
getline()将一直读取到下一个分隔符或换行符或文件结尾

为什么不尝试getline(),它接受分隔符作为第三个参数

string buffer;
for (int c = 0; c < M; ++c) {
    getline(file, buffer, ';');
    stringstream tmp(buffer);
    tmp>>*(A + N*c + r);
}
字符串缓冲区;
对于(int c=0;c>*(A+N*c+r);
}


getline()将一直读取,直到下一个分隔符或换行符或文件结尾

所有
*(A+N*c+r)
都可以更改为
A[N*c+r]
。你需要给出一个更好的测试用例来准确地说明你要做什么。因为问题已经写好了,我可以编写一个程序,每行读三个字符,我猜这不是你想要的。timrau,是的,但这不应该是个问题。@RedRoboHood我是按照我的目标编辑的。我想测试用例很好,我想用文件的数字填充矩阵。@gsamaras测试用例的问题是,它使每个数字看起来都是相同的宽度,或者更糟糕的是,每个数字正好是一个字符。这真的是真的吗?矩阵中的空格和分号似乎不被您的代码。可能在第一个(对于int c)语句中使用c+=3而不是++c。所有
*(A+N*c+r)
都可以更改为
A[N*c+r]
。你需要给出一个更好的测试用例来准确地说明你要做什么。因为问题已经写好了,我可以编写一个程序,每行读三个字符,我猜这不是你想要的。timrau,是的,但这不应该是个问题。@RedRoboHood我是按照我的目标编辑的。我想测试用例很好,我想用文件的数字填充矩阵。@gsamaras测试用例的问题是,它使每个数字看起来都是相同的宽度,或者更糟糕的是,每个数字正好是一个字符。这真的是真的吗?矩阵中的空格和分号似乎不被您的代码。可能在第一步使用c+=3而不是++c(对于int c)语句谢谢。你知道如果每行的最后一个数字也有分号,我该怎么办吗?例如,第一行是这样的
1;2;3;4;5;
,而不是这样的
1;2;3;4;5
。不,我在抛出'std::invalid_argument'what()实例后被调用
terminate:stod
std::string temp;do{file>>temp;temp.erase(std::remove(temp.begin(),temp.end(),“;”),temp.end();)while(temp.size()==0);*(A+N*c+r)=std::stod(temp)
您应该更改您的测试值,使其在行尾包含分号,我可以在我的答案中使用修改后的代码,然后您的分号在末尾有一个空格,因此将分别读入
temp
字符串
:您可以使用
if(temp=“;”)继续;
替换之前替换它以忽略它。谢谢。您知道如果每行的最后一个数字也有分号,我该怎么办吗?例如,第一行是这样的
1;2;3;4;5;
而不是这样的
1;2;3;4;5
。不,我在抛出一个'std::invalid_argument'what():stod
>temp;temp.erase(std::remove(temp.begin()、temp.end()、';')、temp.end());}而(temp.size()==0);*(A+N*c+r)=std::stod(temp)
您应该更改您的测试值,使其在行尾包含分号,我可以在我的答案中使用修改后的代码,然后您的分号在末尾有一个空格,因此将分别读入
temp
字符串
:您可以使用
if(temp=“;”)继续;
替换之前忽略它。哦,这是有意义的。是的,你是对的,我只是做了一个小示例,没有启用标志。哦,这是有意义的。是的,你是对的,我只是做了一个小示例,没有启用标志。但是,我同意Tony,断言会被触发,因为你需要
断言(应为_分号==';');
,它应该是if语句正文的一部分。@gsamaras:dam,,,我经常调用这样的变量