如何在C ++中的.txt文件中查找值?

问题描述 投票:0回答:1

我需要从.txt文件中提取复杂值,并将其分配给4个数组(4个复杂矩阵3 * 3),然后在它们之间执行+,-,*,/,*(-0.8 + 1.6i)操作。我需要使用什么来在txt文件中查找并获取这些复杂值?

这是.txt文件的简短版本。

# file.txt 
# some text bla bla 123
# same
-2.3-14.6i,9.1
7.1+2.8i-7.1-11.7i
# bla bla 

现在我做了什么。

struct comp
    {
        double x, y;
    };

    comp arr[100];
    ifstream infile("C:\\Users\\Nick Leeker\\Desktop\\data.txt");

    if (!infile)    // Does file open correctly?
    {
        cout << "error -1\n\n";
        return -1;
    }
    else
    {
        cout << "file is open\n\n";
        return 1;
    }
c++ ifstream complex-numbers
1个回答
0
投票

首先,C ++库提供了一个std::complex,您可以使用它来代替comp结构。使用标准的复杂类型将提供比struct更多的功能。但是,使用struct comp进行学习以解析文件中所需的信息并没有错。

无论您使用提供的std::complex还是自己的struct comp,如果要存储所有复杂值以便它们可用,您将需要创建一个std::vector来保存所有值,而不是简单的旧数组comp。 (让STL处理内存管理和存储-与从头开始自行编写相比,它不容易出错)

请勿在代码中使用Magic-NumbersHardcode Filenames。 (这就是main()接受参数int main (int argc, char **argv)的原因。将文件名作为参数传递给main()或将文件名作为输入。(如果未提供默认文件名,则可以提供默认文件名)。为文件名指定一个参数,并声明您的std::vector<comp>并打开并验证您的文件是否打开,可以执行以下操作:

...
struct comp {       /* your struct of complex type */
    double x, y;
};

int main (int argc, char **argv) {

    if (argc < 2) {     /* validate 1 argument given for filename */
        std::cerr << "error: filename required as argument"
                    "usage: " << argv[0] << " filename\n";
        return 0;
    }
    std::vector<comp> cmplx;            /* vector of comp */
    std::string arr;                    /* string to read each line */
    std::ifstream infile (argv[1]);     /* open file given as 1st argument */

    if (!infile.good()) {   /* validate file open */
        std::cerr << "error: file open failed '" << argv[1] << "'.\n";
        return 1;   /* don't return negative values to the shell */
    }
    ...

要从文件中读取复数值,您需要一次将一行数据读入arr。然后,您想从std::stringstream创建一个arr,使您可以使用','分隔符从字符串流中读取包含复杂值的字符串。 (您不能将','分隔符用于从文件中读取,getline不会知道行的结尾,而忽略每行末尾的'\n'来查找下一个',',就可以跳过该行) )

因此,您只需将行放入stringstream中并从stringstream中读取(stringstream中只有一行数据,因此没有机会读取末尾的数据)。例如:

    ...
    while (getline (infile, arr)) {     /* read each line */
        if (arr.at(0) == '#')           /* if comment line, get next */
            continue;
        std::string s;                  /* string to read from ss */
        std::stringstream ss(arr);      /* create stringstream from arr */
        ...

就像您正在通过上面的循环从文件中循环读取getline的行一样,现在您只需以类似的方式使用第二个循环从字符串流中读取由','分隔的字符串。在循环中,您将需要获取当前字符串的长度,保留从字符串开头的偏移量变量,以与substr一起使用,以告诉stod从哪里开始读取下一个值,您将想要声明一个pos(位置)值,以std::stod填充,告诉您在将行的当前部分转换为double时使用了多少个字符,因此可以将其添加到偏移量中以了解开始阅读下一个。参见std::stof, std::stod, std::stold

您还将想要声明一个temporary struct comp实例,以填充转换为double的值,如果对两个vector值的解析都成功,则可以将其添加到x, y中:

        ...
        while (getline (ss, s, ',')) {  /* read with ',' delimiter */
            size_t  len = s.length(),   /* length to check if done reading */
                    off = 0,            /* offset from beginning of s */
                    pos = 0;            /* chars reported used by stod */
            comp tmp;                   /* temporary struct to fill */
            ...

使用std::stod转换时,必须使用try {...} catch (exception) {...}捕捉转换期间的任何错误,以便您可以正确处理该错误。读取实部(x)后,将使用转换中使用的字符数(由s报告)更新pos中的偏移量,以了解从何处开始虚部的转换(如果没有虚部,则将值设置为零),例如

            ...
            try {   /* you must validate conversion with exceptions */
                tmp.x = stod (s.substr(off), &pos);
            }
            catch (const std::exception & e) {  /* error in 1st conversion */
                std::cerr << "error invalid tmp.x: "<< e.what() << '\n';
                continue;   /* get next potential complex no. */
            }
            off += pos;         /* real part obtained, update offset with pos */
            if (len > off) {    /* check chars remain to parse imaginary */
                try {   /* validate with exception */
                    tmp.y = stod (s.substr(off), &pos);
                }
                catch (const std::exception & e) {  /* warn on failed parse */
                    std::cerr << "no value for tmp.y: "<< e.what() << '\n';
                }
            }
            else        /* if no chars for imaginary part, set to zero */
                tmp.y = 0;
            ...

[note:由于您已经阐明了虚数之间将存在',',因此您可以在调用中简单地使用s而不是s.substr(off)将实数部分转换为两倍。如果substr是可选的以允许使用','的定界符,然后检查下一个字符是否为'i',这将需要在第一次调用时使用',',则需要使用off == 1 >

剩下的就是将您填充的临时struct comp添加到向量中,例如

            ...
            cmplx.push_back(tmp);   /* add temporary comp to vector */
        }
    }

基本上就是这样。您已填满std::vector<comp> cmplx,将从文件中读取所有复数值。您可以简单地输出它们以验证结果,例如

    ...
    std::cout << "results\n\n";     /* output results */
    for (auto& c : cmplx)
        std::cout << "(" << c.x << ", " << c.y << "i)\n";
}

将其完全放入:

#include <iostream>
#include <fstream>
#include <sstream>
#include <string>
#include <vector>

struct comp {       /* your struct of complex type */
    double x, y;
};

int main (int argc, char **argv) {

    if (argc < 2) {     /* validate 1 argument given for filename */
        std::cerr << "error: filename required as argument"
                    "usage: " << argv[0] << " filename\n";
        return 0;
    }
    std::vector<comp> cmplx;            /* vector of comp */
    std::string arr;                    /* string to read each line */
    std::ifstream infile (argv[1]);     /* open file given as 1st argument */

    if (!infile.good()) {   /* validate file open */
        std::cerr << "error: file open failed '" << argv[1] << "'.\n";
        return 1;   /* don't return negative values to the shell */
    }

    while (getline (infile, arr)) {     /* read each line */
        if (arr.at(0) == '#')           /* if comment line, get next */
            continue;
        std::string s;                  /* string to read from ss */
        std::stringstream ss(arr);      /* create stringstream from arr */
        while (getline (ss, s, ',')) {  /* read with ',' delimiter */
            size_t  len = s.length(),   /* length to check if done reading */
                    off = 0,            /* offset from beginning of s */
                    pos = 0;            /* chars reported used by stod */
            comp tmp;                   /* temporary struct to fill */
            try {   /* you must validate conversion with exceptions */
                tmp.x = stod (s.substr(off), &pos);
            }
            catch (const std::exception & e) {  /* error in 1st conversion */
                std::cerr << "error invalid tmp.x: "<< e.what() << '\n';
                continue;   /* get next potential complex no. */
            }
            off += pos;         /* real part obtained, update offset with pos */
            if (len > off) {    /* check chars remain to parse imaginary */
                try {   /* validate with exception */
                    tmp.y = stod (s.substr(off), &pos);
                }
                catch (const std::exception & e) {  /* warn on failed parse */
                    std::cerr << "no value for tmp.y: "<< e.what() << '\n';
                }
            }
            else        /* if no chars for imaginary part, set to zero */
                tmp.y = 0;

            cmplx.push_back(tmp);   /* add temporary comp to vector */
        }
    }

    std::cout << "results\n\n";     /* output results */
    for (auto& c : cmplx)
        std::cout << "(" << c.x << ", " << c.y << "i)\n";
}

示例使用/输出

将数据保存在文件dat/cmplx.txt中,运行程序并分析文件中的值将导致:

$ ./bin/parse_complex dat/cmplx.txt
results

(-2.3, -14.6i)
(9.1, 0i)
(7.1, 2.8i)
(-7.1, -11.7i)

仔细检查,如果还有其他问题,请告诉我。

© www.soinside.com 2019 - 2024. All rights reserved.