Pythonで文字列をfloatまたはintに解析するにはどうすればよいですか?



Answers

def num(s):
    try:
        return int(s)
    except ValueError:
        return float(s)
Question

Pythonでは、 "545.2222"ような数値文字列を対応するfloat値、 542.2222にどのように解析できますか? または、文字列"31"を整数"31"解析します。

私は浮動小数点数を浮動小数点数に解析する方法と、(別に) 整数を整数に変換する方法を知りたいだけです。




適切にこれを行うには丸めを考慮する必要があります。

つまり、int(5.1)=> 5 int(5.6)=> 5 - 間違っているので、6にする必要があります。int(5.6 + 0.5)=> 6

def convert(n):
    try:
        return int(n)
    except ValueError:
        return float(n + 0.5)



YAMLパーサーは、あなたの文字列がどんなデータ型であるかを理解するのに役立ちます。 yaml.load()使用すると、 type(result)を使用してtype(result)をテストできます:

>>> import yaml

>>> a = "545.2222"
>>> result = yaml.load(a)
>>> result
545.22220000000004
>>> type(result)
<type 'float'>

>>> b = "31"
>>> result = yaml.load(b)
>>> result
31
>>> type(result)
<type 'int'>

>>> c = "HI"
>>> result = yaml.load(c)
>>> result
'HI'
>>> type(result)
<type 'str'>



第三者のモジュールを嫌う人なら、 fastnumbersモジュールをチェックすることができます。 これはfast_realという関数を提供しています。この関数は、この質問が尋ねていることを正確に行い、純粋なPythonの実装よりも高速です。

>>> from fastnumbers import fast_real
>>> fast_real("545.2222")
545.2222
>>> type(fast_real("545.2222"))
float
>>> fast_real("31")
31
>>> type(fast_real("31"))
int



質問は少し古いようです。 しかし、parseStrという関数を提案しましょう。これは、何か似たようなもの、つまり整数または浮動小数点数を返します。また、指定されたASCII文字列を変換できない場合はそのまま返します。 コードは、あなたが望むものだけを行うように調整することができます:

   >>> import string
   >>> parseStr = lambda x: x.isalpha() and x or x.isdigit() and \
   ...                      int(x) or x.isalnum() and x or \
   ...                      len(set(string.punctuation).intersection(x)) == 1 and \
   ...                      x.count('.') == 1 and float(x) or x
   >>> parseStr('123')
   123
   >>> parseStr('123.3')
   123.3
   >>> parseStr('3HC1')
   '3HC1'
   >>> parseStr('12.e5')
   1200000.0
   >>> parseStr('12$5')
   '12$5'
   >>> parseStr('12.2.2')
   '12.2.2'



あなたの質問の別の解釈があります(ヒント:あいまいです)。 次のようなものを探している可能性があります。

def parseIntOrFloat( aString ):
    return eval( aString )

それはこのように動作します...

>>> parseIntOrFloat("545.2222")
545.22220000000004
>>> parseIntOrFloat("545")
545

理論的には、注射の脆弱性があります。 文字列は、例えば"import os; os.abort()" 。 しかし、文字列がどこから来るのかについての背景なしに、理論的な推測の可能性がある。 問題はあいまいなので、この脆弱性が実際に存在するかどうかはまったく明らかではありません。




ローカリゼーションとコンマ

例外をスローするfloat("545,545.2222")ような場合には、数値の文字列表現でカンマの可能性を考慮する必要があります。 代わりに、 localeメソッドを使用して文字列を数値に変換し、カンマを正しく解釈します。 locale.atofメソッドは、ロケールが目的の番号規則のために設定されると、フロートに一度に変換されます。

例1 - 米国の番号規則

米国と英国では、カンマを千単位の区切り記号として使用できます。 この例では、アメリカのロケールでは、カンマがセパレータとして正しく処理されます。

>>> import locale
>>> a = u'545,545.2222'
>>> locale.setlocale(locale.LC_ALL, 'en_US.UTF-8')
'en_US.UTF-8'
>>> locale.atof(a)
545545.2222
>>> int(locale.atof(a))
545545
>>>

例2 - ヨーロッパの番号規則

世界大部分の国では 、ピリオドの代わりにカンマが小数点記号として使用されています。 フランス語のロケールを使用したこの例では、コンマは小数点として正しく処理されます。

>>> import locale
>>> b = u'545,2222'
>>> locale.setlocale(locale.LC_ALL, 'fr_FR')
'fr_FR'
>>> locale.atof(b)
545.2222

メソッドlocale.atoiも使用できますが、引数は整数でなければなりません。




私は正規表現を誰も言及しなかったのは驚くべきことです。時には文字列を数値に変換する前に準備して正規化しなければならないからです

import re
def parseNumber(value, as_int=False):
    try:
        number = float(re.sub('[^.\-\d]', '', value))
        if as_int:
            return int(number + 0.5)
        else:
            return number
    except ValueError:
        return float('nan')  # or None if you wish

使用法:

parseNumber('13,345')
> 13345.0

parseNumber('- 123 000')
> -123000.0

parseNumber('99999\n')
> 99999.0

ちなみに、番号があることを確認するための何か:

import numbers
def is_number(value):
    return isinstance(value, numbers.Number)
    # will work with int, float, long, Decimal



私はこの機能を

import ast

def parse_str(s):
   try:
      return ast.literal_eval(str(s))
   except:
      return

文字列をその型に変換します

value = parse_str('1')  # Returns Integer
value = parse_str('1.5')  # Returns Float



つかいます:

def num(s):
    try:
        for each in s:
            yield int(each)
    except ValueError:
        yield float(each)
a = num(["123.55","345","44"])
print a.next()
print a.next()

これは私が思いつくことができる最もPythonの方法です。




これはここで言及する価値のある別の方法です、 ast.literal_eval

これは、値を解析する必要なく、信頼できないソースからPython式を含む文字列を安全に評価するために使用できます。

つまり、安全な「評価」は、

>>> import ast
>>> ast.literal_eval("545.2222")
545.2222
>>> ast.literal_eval("31")
31



Related