输入文件

时间:2018-03-04 23:49:30

标签: c++

我正在尝试创建一个程序,我有一个.txt文件并使用我的程序读取该文件。我的程序应该能够添加或减去数字并显示总和。我目前已经到了可以成功添加或减去文件中的数字的地步。当我尝试取一个数字的平方时,我出现了问题。例如,这就是文本文件的外观。

8 ^;

6 ^ + 3;

900 + 5 ^ - 4 ^ + 2 - 9;

期望的输出应该如下所示

64

39

902

到目前为止,我只能在没有涉及平方的情况下处理答案。但当我把平方包括在内时,一切都变得令人困惑。如果有人可以帮助我走上解决方案的正确道路,我将非常感激。

int main() {
//Initialize variables
int sum = 0;
char operation;
int number;
int holdingnumber;
int holdingoperation;
int operationChecker;
ifstream fileChecker;

//Open file
fileChecker.open("data.txt");

//If file didn't open exit program
if (!fileChecker) {
    cout << "The file could not be found/opened!";
    exit(1);
}

//Read information from file and add to variable sum
fileChecker >> number;
sum = number;
while (fileChecker >> operation >> number)
{
    if (operation == ';')
    {
        cout << sum << endl;
        sum = number;
    }
    else if (operation == '^')
    {
        holdingnumber = holdingnumber * holdingnumber;
        if (holdingoperation == '+')
        {
            sum = sum + holdingnumber;
        }
        else if (holdingoperation == '-')
        {
            sum = sum - holdingoperation;
        }
    }
    else if (operation == '+')
    {
        holdingoperation = operation;
        holdingnumber = number;
    }
    else if (operation == '-')
    {
        holdingoperation = operation;
        holdingnumber = number;
    }
}

//Close file and display sum
fileChecker.close();
cout << sum;
return 0;
}

1 个答案:

答案 0 :(得分:0)

您(或将要)遇到最大问题的原因是您创建了一个非常脆弱的输入例程,该例程依赖于输入文件的>> number >> operator格式。为什么你在实现平方部分代码时遇到问题,关于广场的输入格式有额外的计算并不仅仅遵循>> number >> operator,还包括>> operator >> number

例如:

900 + 5^ - 4^ + 2 - 9;

>> number >> operator >> number >> operator >> operator >> number operator >> operator >> number >> operator >> number >> delimiter

虽然无论如何操作都会有嵌套条件,但除了根据它们处理各种计算之外,当你开始在read语句中添加其他条件时,所需的数字很快就会失控。

在上面的代码中,如果您将>>更改为scanf次调用,将<<更改为printf,则您的代码不会使用C ++提供的任何内容。 C ++提供了一组很好的工具,可以帮助您处理这些事物的值,字符串,字符和集合。利用语言提供的功能。

此处,使用stringvector类,无需管理holding...变量。它可以这样做,同时完全消除您在行末有分隔符(例如';')的依赖性。 (事实上​​唯一的挑战是,如果你找到一个由';'分隔的行,你只需将其删除)

更好的阅读文件的方法是一次读一行string getline。这使得循环遍历文件很简单,只需将每行读入字符串,直到没有更多的行可读。

C ++提供自动范围迭代器(以及其他几个),然后让你迭代字符串(行)中的每个字符。 <cctype>标头提供isdigit()函数,允许您确定当前char是否为允许您获取数值的数字。通过调用vector成员函数将该值添加到向量中,push_back()类可以轻松存储该值(以及根据需要添加更多值)。

(注意:您可以轻松地在存储的字符串上使用 stringstream ,并根据stoi等转换例程解析这些值,但对于简单数字(假定为非负数 - 意味着'-'是一个运算符,并且不包含代码来处理'- -value',但可以很容易地添加代码。

当遇到运算符时,向量类提供了一个简单的.size()成员函数,允许您告知向量中有多少值正在等待。然后,它只是一个逻辑游戏,知道+, -, *, /将对向量中的最后相邻值进行操作,而'^'仅对最后一个进行操作。

如果您将向量中的最后一个值保留为当前sum,那么在处理给定的所有计算时,您不必跟踪任何其他变量(临时使用除外)线。

当您处理完一行后,您的计算文本已存储在您的字符串中,因此在处理完一行后,您只需输出您的计算字符串然后输出结果(存储的最后一个值)你的矢量):

cout << string << " = " << vector.back() << "\n";

将所有部分组合在一起,您可以执行与以下类似的操作。稍微考虑一下,你可能会找到一个更好的方法来做到这一点。关键是,总会有很多方法来解决问题:

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

using std::ifstream;
using std::cout;
using std::cerr;
using std::string;
using std::vector;

/* execute current calculation between adjacent values */
void execute (vector<long>& values, char op);

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

    long tmp = 0;   /* temp number to build values as chars processed */
    string calc;    /* string to hold the line (complete calculation) */
    ifstream f (argc > 1 ? argv[1] : "data.txt");   /* file to read */

    if (!f.is_open()) { /* validate file open for reading */
        cerr << "error: file open failed.\n";
        return 1;
    }

    while (getline (f, calc)) {     /* loop over each line in the file */
        char op = 0;                /* char to hold operator (+,-,*,/) */
        vector<long> values;        /* vector to hold adjacent values */
        if (calc.back() == ';')     /* if line delimited by ';', then */
            calc.pop_back();        /* remove ';' from string */
        for (auto& c : calc) {      /* for each char in line */
            if (isdigit(c)) {       /* am I a digit?, if so build value */
                tmp *= 10;
                tmp += c - '0';
            }
            else {  /* if I'm not a digit, I'm either whitespace or op */
                if (tmp) {              /* if there is a value in temp */
                    values.push_back (tmp); /* add the value to vector */
                    tmp = 0;                /* zero tmp */
                }
                if (values.size() && c == '^') {     /* handle squared */
                    values.back() *= values.back();  /* square in place */  
                }
                else if (values.size() > 1 && op) { /* adjacent vals & op */
                    execute (values, op);   /* computer intermediate calc */
                    op = 0;                 /* op consumed, reset to zero */
                }
                else {  /* not digit, not squaring, no adjacent vales */
                    switch (c) {    /* save op if one of following */
                        case '+':   op = c; break;
                        case '-':   op = c; break;
                        case '*':   op = c; break;
                        case '/':   op = c; break;
                    }
                }
            }
        }   /* all characters processed */
        if (tmp) {                      /* does tmp value remain? */
            values.push_back (tmp);     /* add to vector */
            tmp = 0;                    /* reset tmp */
        }
        if (values.size() > 1 && op)    /* handle final calculation */
            execute (values, op);
        cout << calc << " = " << values.back() << "\n";
    }
    f.close();
}

/* simple function takes vector reference and operator
 * and performs indicated calculation on adjacent values.
 */
void execute (vector<long>& values, char op)
{
    long sum;
    auto it = values.end();
    it -= 2;
    switch (op) {
        case '+':   sum = *it + values.back();
                    values.pop_back();
                    values.back() = sum; 
                    break;
        case '-':   sum = *it - values.back();
                    values.pop_back();
                    values.back() = sum; 
                    break;
        case '*':   sum = *it * values.back();
                    values.pop_back();
                    values.back() = sum; 
                    break;
        case '/':   sum = *it / values.back();
                    values.pop_back();
                    values.back() = sum; 
                    break;
    }
}

注意:)使用上面的pop_back()来修剪向量中的最后一个元素,允许您将运行总计作为向量中的最终(且唯一)值基本上,计算完成后,如果它涉及两个值,在计算完成后,矢量中的最后一个值将被删除,当前总数将被存储到该计算的第一个值的位置。

另请注意,这是一个简单的示例,除了解决输入数据文件的方法之外,其他任何内容都不适用。

示例输入文件

没有行尾分隔符:

$ cat ../dat/calc.txt
127 + 231
8^
6^ + 3
900 + 5^ - 4^ + 2 - 9

使用分隔符:

$ cat ../dat/calcdelim.txt
127 + 231;
8^;
6^ + 3;
900 + 5^ - 4^ + 2 - 9;

示例使用/输出

无论使用哪个输入文件,输出都是相同的。

$ ./bin/calctest ../dat/calc.txt
127 + 231 = 358
8^ = 64
6^ + 3 = 39
900 + 5^ - 4^ + 2 - 9 = 902

仔细看看。消化语言的不同部分需要时间。这是一些很好的参考引用帮助,如cppreference.com。如果您有任何其他问题,请与我们联系。