2009-02-22 11 views

答えて

16

変換が失敗した場合、私は文字列を解析したい:

>>> def convert(s): 
    try: 
     return float(s) 
    except ValueError: 
     num, denom = s.split('/') 
     return float(num)/float(denom) 
... 

>>> convert("0.1234") 
0.1234 

>>> convert("1/2") 
0.5 

を一般的にはevalを使用して、それはセキュリティ上のリスクなので、悪い考えです。 特に評価される文字列がシステムの外部から来た場合はとなります。

+1

+1。この場合、evalはまったく必要ありません。誰か(私以外はもちろん)が正しいことに気づいてくれてうれしいです。 –

+0

あなたの同僚が悪意のある社会病者でない限り、Evalはセキュリティリスクではありません。この場合、あなたはそれを必要としませんが、オープンソースコード自体よりもセキュリティ上のリスクはありません。 –

+0

非常に良い。文字列は実際に外から来たので、私は安全に行く必要があります(悪い習慣を学ばないようにしてください)。私はそれを解析する必要がないことを望んでいたが、これはあまりにも悪くないし、魅力のように動作します。 – ketorin

3

/オペレータは整数の除算しません:

のevalは、私が考えていたが、運ものです。試してみてください:

>>> eval("1.0*" + "1/2") 
0.5 

eval()が潜在的に危険なので、あなたは常にあなたがそれに渡しているものを正確に確認する必要があります:

>>> import re 
>>> s = "1/2" 
>>> if re.match(r"\d+/\d+$", s): 
...  eval("1.0*" + s) 
... 
0.5 

しかし、あなたが正規表現に対して、入力のマッチングのトラブルに行けば最初の場所は、あなたにも分裂自分で行う、分子と分母を抽出するためにr"(\d+)/(\d+)$"を使用して、完全に避けるかもしれないeval()

>>> m = re.match(r"(\d+)/(\d+)$", s) 
>>> if m: 
...  float(m.group(1))/float(m.group(2)) 
... 
0.5 
+0

おかげで、evalのヒントは、今にいいです、私は私が指摘したように、安全なソリューションを必要実現していることを除いて...ちょうど素晴らしい仕事をするだろうでる。 – ketorin

0

これは、1と2がPythonによって整数として解釈され、浮動小数点ではないためです。それは1.0/2.0またはその何らかの組み合わせである必要があります。

4

from __future__ import divisionを使用すると、必要な動作が得られます。次にピンチで、あなたの文字列の浮き出しのリストを得るために

from __future__ import division 
strings = ["0.1234", "1/2", "2/3"] 
numbers = map(eval, strings) 

のような何かをすることができます。これを「正しい」方法で行いたい場合は、eval()を使用せず、スラッシュを含まない場合は文字列を受け取り、float()を呼び出す関数を記述するか、文字列を解析して分子と分母を除算しますその中にスラッシュ。それを行うには

一つの方法:

def parse_float_string(x) 
    parts = x.split('/', 1) 
    if len(parts) == 1: 
     return float(x) 
    elif len(parts) == 2: 
     return float(parts[0])/float(parts[1]) 
    else: 
     raise ValueError 

それからちょうどmap(parse_float_string, strings)は、あなたのリストを取得します。

2

evalの問題は、Pythonの場合と同様に、整数の商が整数であることです。だから、いくつかの選択肢があります。

from __future__ import division 

他方は有理数を分割することである:

最初は単純に整数除算リターンが浮かぶようにすることである

rat_strが有理数の文字列である
reduce(lambda x, y: x*y, map(int, rat_str.split("/")), 1) 

0

from __future__ import divisionの提案とevalの組み合わせが有効です。

それはおそらくevalは危険ですのでevalを使用するのではなく、文字列を解析していない提案がそうすることを指摘する価値がある:evalに送信され得るために、任意の文字列のためにいくつかの方法がある場合、その後、あなたのシステムが脆弱です。だから、それは悪い習慣です。 (これは単に迅速かつ汚いコードであるなら、それはおそらくないその大したことです!)他の人が指摘したように

7

evalは潜在的なセキュリティリスク、確かに入るために悪い癖である使用します。あなたは、最大のpython 2.6またはを持っている場合は、文字列が提供されるast.literal_evalを、使用することができ、

しかし: (__import__('os').system('rm -rf /')あなたはそれがexecと同じくらい危険ではないと思う場合は、のようなeval INGの何かを想像):

は、 文字列、 数字、タプル、リスト、ディクテーション、 ブーリアン、およびなしの文字列でのみ構成できます。

したがって、それは(もわずか2.6とアップのために)

+0

それについて知りませんでした - ありがとう! –

+0

真剣に混乱している同僚をいなくても、例のように何かを悪意のあるものとして評価することは可能ですか? Evalはセキュリティリスクではなく、シェルへのアクセスはセキュリティリスクです。 –

+0

公正なポイント..あなたが信頼できない入力を扱っていないなら、evalは危険ではありません。私はこの投稿の影響を受けていると思う:http://phpxmlrpc.sourceforge.net/#security - PHPの人は、evalを取り除かなければならないことを理解する前に、問題を2回解決しようとした。だから... –

6

:-)もう一つの選択肢は非常に安全でなければなりませんがfractionsモジュールです。

>>> from fractions import Fraction 
>>> Fraction("0.1234") 
Fraction(617, 5000) 
>>> Fraction("1/2") 
Fraction(1, 2) 
>>> float(Fraction("0.1234")) 
0.1234 
>>> float(Fraction("1/2")) 
0.5 
1

これは動作するはずです。

>>> x = ["0.1234", "1/2"] 
>>> [eval(i) for i in x] 
[0.1234, 0.5] 
+1

いいえ、Python 3では、 'from __future__ import division'をデフォルトにしました... Python 3では、将来は今です! – kquinn

1

sympyがここであなたを助けることができます。

import sympy 

half = sympy.Rational('1/2') 
p1234 = sympy.Rational('0.1234') 
print '%f, %f" % (half, p1234) 
関連する問題