我想对单位转换器进行编码,我需要从输入字符串中的单位中提取给定值。
为了在使用转换器时提供用户友好的体验,我希望用户能够在同一字符串中输入值和单位。我的问题是我想提取数字和字母,以便可以告诉程序单位和值并将它们存储在两个不同的变量中。为了提取字母,我使用了in
运算符,它可以正常工作。我还找到了一种从输入中获取数字的解决方案,但这不适用于具有指数的值。
a = str(input("Type in your wavelength: "))
if "mm" in a:
print("Unit = Millimeter")
b = float(a.split()[0])
将诸如567 mm
之类的简单输入存储为b
的浮点型是可行的,但我希望能够提取诸如5*10**6 mm
之类的输入,但它说
could not convert string to float: '5*10**6'.
那么我该如何使用类似的方法将更复杂的数字提取到浮点数中?
答案 0 :(得分:1)
传统上,在Python中,就像在许多其他语言中一样,指数以字母e
或E
为前缀。虽然5 * 10**6
不是有效的浮点文字,但5e6
绝对是。
这是将来要记住的事情,但是它不能解决in
运算符的问题。问题在于in
仅可以检查您已经知道的东西是否存在。如果您输入的是5e-8 km
怎么办?
您应该首先明确地定义如何识别字符串中数字和单位之间的边界。例如,单位可以是字符串中非数字字符的最后一个连续位。
然后可以使用regular expressions分割字符串。由于第一部分可以是任意表达式,因此您可以使用ast.literal_eval
这样的简单值对其进行求值。表达式越复杂,解析器就必须越复杂。
这是一个让您入门的示例:
from ast import literal_eval
import re
pattern = re.compile(r'(.*[\d\.])\s*(\D+)')
data = '5 * 10**6 mm'
match = pattern.fullmatch(data)
if not match:
raise ValueError('Invalid Expression')
num, units = match.groups()
num = literal_eval(num)
答案 1 :(得分:0)
似乎您正在寻找eval
函数,如@Rasgel的答案所述。 Documentation here
正如某些人指出的那样,这带来了很大的安全风险。
为避免这种情况,我可以想到2种方法:
1。将eval
与正则表达式结合使用
如果您只想执行基本的算术运算,例如加法,减法以及诸如此类的2**4
或某事,则可以使用正则表达式首先删除所有非数字,非算术运算符。
import re
a = str(input("Type in your wavelength: "))
if "mm" in a:
print("Unit = Millimeter")
# After parsing the units,
# Remove anything other than digits, +, -, *, /, . (floats), ! (factorial?) and ()
# If you require any other symbols, add them in
pruned_a = re.sub(r'[^0-9\*\+\-\/\!\.\(\)]', "", a)
result = eval(pruned_a)
2。确保eval实际上没有评估python代码中的任何局部或全局变量。
result = eval(expression, {'__builtins__': None}, {})
(以上代码来自另一个Stackoverflow答案:Math Expression Evaluation-可能还有其他您可能感兴趣的解决方案)
组合
import re
a = str(input("Type in your wavelength: "))
if "mm" in a:
print("Unit = Millimeter")
# After parsing the units,
# Remove anything other than digits, +, -, *, /, . (floats), ! (factorial?) and ()
# If you require any other symbols, add them in
pruned_a = re.sub(r'[^0-9\*\+\-\/\!\.\(\)]', "", a)
result = eval(pruned_a, {'__builtins__': None}, {}) #to be extra safe :)
答案 2 :(得分:0)
使用str.split
,regular expressions
,eval
,ast.literal_eval
有很多方法可以解决这个简单的问题...在这里,我建议您拥有自己的安全例程将评估简单的数学表达式的代码如下:
import re
import ast
import operator
def safe_eval(s):
bin_ops = {
ast.Add: operator.add,
ast.Sub: operator.sub,
ast.Mult: operator.mul,
ast.Div: operator.itruediv,
ast.Mod: operator.mod,
ast.Pow: operator.pow
}
node = ast.parse(s, mode='eval')
def _eval(node):
if isinstance(node, ast.Expression):
return _eval(node.body)
elif isinstance(node, ast.Str):
return node.s
elif isinstance(node, ast.Num):
return node.n
elif isinstance(node, ast.BinOp):
return bin_ops[type(node.op)](_eval(node.left), _eval(node.right))
else:
raise Exception('Unsupported type {}'.format(node))
return _eval(node.body)
if __name__ == '__main__':
text = str(input("Type in your wavelength: "))
tokens = [v.strip() for v in text.split()]
if len(tokens) < 2:
raise Exception("expected input: <wavelength expression> <unit>")
wavelength = safe_eval("".join(tokens[:-1]))
dtype = tokens[-1]
print(f"You've typed {wavelength} in {dtype}")
我也建议您阅读这篇文章Why is using 'eval' a bad practice?
答案 3 :(得分:-3)
如果您有一个类似5*106
的字符串,并且想要将此数字转换为浮点数,则可以使用eval()
函数。
>>> float(eval('5*106'))
530.0