2017-12-02 299 views
3

我目前正在尝试处理从用户处获取输入的代码,要求他们打开包含数学问题的文件,然后输出一个解决这些问题的文件。我一直在寻求某种形式的解决方案,这一切都结束了,但这些都是我得到的最接近:将带数学问题的文本文件转换为带有这些问题的答案的文本文件

文本文件的内容:

2 + 2

3 * 3

4.5 - 2.3

-8.8 + 1.2

2^4

8.9/2.3

5%3

-2 * -2

尝试1:

input_file_name = input("What file would you like to open? ") 
output_file_name = input("What file would you like to write to? ") 

with open(input_file_name,"r") as input_file: 
    contents = input_file.readlines() 
    num = "".join(contents) 
    contents_length = len(num) 

with open(output_file_name, "w") as output_file: 
    while contents_length >= 0: 
     num = num.replace("^","**") # change the^to ** so python can properly do the function 
     contents_value = exec(num) 

     contents_length = contents_length - 1 

    output_file.write(str(contents_value)) 

我接收到的文本文件将返回 “无”

尝试2:

input_file_name = input("What file would you like to open? ") 
output_file_name = input("What file would you like to write to? ") 

infile = open(input_file_name, "r") 
outfile = open(output_file_name, "w") 

lines = infile.readlines() 

i = len(lines) - 1 

while i >= 0: 
    ans = eval(lines[i]) 
    outfile.write(str(ans)) 
    i = i - 1 

infile.close() 
outfile.close() 

而且文本文档文件中有423.86956521739130476-7.60000000000000052.294。

所以,我真的不知道还有什么要做。任何帮助将不胜感激。

回答

1

您需要单独处理的每一行,但是这个代码

num = "".join(contents) 

结合了所有的线到一个单一串。

另一个问题是不需要的小数位。您可以使用round函数修复该问题。下面的代码直接从脚本中读取数据,但很容易使其适用于从文件中读取数据,或者使用.readlines,或者通过简单地循环访问文件对象。

data = '''\ 
2 + 2 
3 * 3 
4.5 - 2.3 
-8.8 + 1.2 
2^4 
8.9/2.3 
5 % 3 
-2 * -2 
'''.splitlines() 

for line in data: 
    line = line.replace('^', '**') 
    s = round(eval(line), 6) 
    print(s) 

输出

4 
9 
2.2 
-7.6 
16 
3.869565 
2 
4 

这是输出使用Python 3.在Python 2中创建的,它不是很干净:一切都会被写为浮动。

的Python 2输出

4.0 
9.0 
2.2 
-7.6 
16.0 
3.869565 
2.0 
4.0 

我假设你知道evalexec一般应当避免,因为它们可能会带来安全风险。详情请参阅SO资深人士Ned Batchelder的Eval really is dangerous。但是我猜你在这里没有多少选择,并且可以保证输入文件不会包含恶意代码。

+0

啊!非常感谢! – bcochran

+0

我没有意识到,我实际上已经了解了eval和exec今天,哈哈。但是,谢谢你的头! – bcochran

+0

如果我希望输出文件具有原始表达式+ = +答案,该怎么办? – bcochran

0

你在第二次尝试中几乎找到了正确的答案。只需添加一个新的行字符每次你正在写的内容到你的文件,我认为它会得到正确的格式

outfile.write(str(ans) + '\n') 

PS我没有测试过,请检查是否有任何语法错误

+0

我想这一点,它确实把所有的“答案”放在他们自己的路线上,但只有第一个问题的答案是正确的。谢谢你,又一步了! 编辑:其实,第一,第四和最后的答案是正确的。 – bcochran

+0

编辑:答案是正确的,只是错误的顺序,哈哈。 – bcochran

+0

我不明白,为什么答案是不正确的顺序? – Ezio

0

是,你是对的,你想使用eval()而不是exec()。

它看起来像你只需要编写每个解决方案后换行即

outfile.write('\n') 
+0

我试过了,虽然每个答案都在自己的路线上,但唯一正确答案是第一个答案。不过谢谢你! – bcochran

+0

编辑:答案是正确的,只是错误的顺序,哈哈。 – bcochran

0

为了论证的缘故,我想证明你没有使用eval在所有您的问题!作为PM 2Ring has warned,使用evalexec是在情况下,安全隐患有任何机会,你正在评估的字符串可以被恶意第三方篡改。许多人关闭此安全风险,但如果你读my favourite answer in the subject你可以看到一个显着简单的例子来执行外蟒蛇任意程序一起eval通话。所以要从未使用上不是100%信任和下控制源eval/exec

回到你的问题,你的例子似乎总是使用val1 OP val2,即两个数字(可能是负数,可能是浮点数)与中缀数学运算符。这个结构非常简单,你可以(我相信应该)为它编写你自己的解析器。这充当了一个演示,通过明确处理我们期望的安全方式的输入,我们可以保证我们的程序在无效和恶意输入上打破。

下面是返回结果为您输入的一行的(一个表达)的函数:

import operator 

def evaluate(expr): 
    '''Evaluate expressions of the form `val1 OP val2`; OP is in [+,-,/,*,%,^]''' 
    ops = { 
     '+': operator.add, 
     '-': operator.sub, 
     '*': operator.mul, 
     '/': operator.truediv, 
     '%': operator.mod, 
     '^': operator.pow, 
     } 
    # gather operators and put minus last so we can handle negative numbers right 
    opskeys = list(ops) 
    ind = opskeys.index('-') 
    implemented_ops = opskeys[ind+1:] + opskeys[:ind+1] 

    for opnow in implemented_ops: 
     if opnow in expr: 
      val1,op,val2 = expr.rpartition(opnow) 
      # convert the numbers to floats, or ints in case they are integral 
      val1,val2 = (int(val) if val.is_integer() else val 
         for val in map(float,[val1,val2])) 
      break 
    else: 
     raise ValueError('Invalid input line "{}"!'.format(expr)) 

    return ops[op](val1,val2) # or round(...,digits) see PM 2Ring's answer 

该函数采用输入的单个线,找到合适的数学运算符,分割使用该字符的行,然后评估结果。它使用调度字典根据字符选择实际的数学运算符;一个好处是我们甚至不需要转换电力运营商。我们将整数输入转换为整数,并将其余部分作为浮点数保留。

函数最后处理减法,这保证了负数不乱了所有其他运营商的计算。这不完全万无一失:如果有料想不到负数无效行,我们很可能会从val1/val2float第一次转换得到ValueError。从负数减去数字或类似的角落案例时,它也可能会中断。可以在代码中添加进一步的保护措施(例如捕获来自float()的异常)我的观点是要证明你可以非常容易地使用安全和可控的方法而不是eval

与您的数据(帽尖再次PM 2Ring)加上有意无效的输入行中运行的一个例子:

data = '''\ 
2 + 2 
3 * 3 
4.5 - 2.3 
-8.8 + 1.2 
2^4 
8.9/2.3 
5 % 3 
-2 * -2 
3 @ 4 
'''.splitlines() 

for line in data: 
    print(evaluate(line)) 

在交互式壳的相应的输出:

4 
9 
2.2 
-7.6000000000000005 
16 
3.8695652173913047 
2 
4 
Traceback (most recent call last): 
    File "<stdin>", line 2, in <module> 
    File "foo.py", line 26, in evaluate 
    raise ValueError('Invalid input line "{}"!'.format(expr)) 
ValueError: Invalid input line "3 @ 4"! 
相关问题