web-dev-qa-db-ja.com

Python、文字列をIntまたはFloatのどちらに変換するかを決定します

文字列を可能な限り厳密なデータ型(intまたはfloat)に変換したいと思います。

私は2つの文字列を持っています:

value1="0.80"     #this needs to be a float
value2="1.00"     #this needs to be an integer.

Pythonでvalue1をFloat、value2をIntegerにする必要があることをどのように判断できますか?

15
ManuParra
def isfloat(x):
    try:
        a = float(x)
    except ValueError:
        return False
    else:
        return True

def isint(x):
    try:
        a = float(x)
        b = int(a)
    except ValueError:
        return False
    else:
        return a == b
22
glglgl

Python floatオブジェクトには is_integerメソッド

from ast import literal_eval
def parses_to_integer(s):
    val = literal_eval(s)
    return isinstance(val, int) or (isinstance(val, float) and val.is_integer())
15
ecatmur
def coerce(x):
    try:
        a = float(x)
        b = int(x)
        if a != b:
            return a
        else:
            return b
    except:
        raise ValueError("failed to coerce str to int or float")
5
ZuLu

これを行う別の方法は、次のような正規表現を使用することです。

import re
def parse_str(num):
    """
    Parse a string that is expected to contain a number.
    :param num: str. the number in string.
    :return: float or int. Parsed num.
    """
    if not isinstance(num, str): # optional - check type
        raise TypeError('num should be a str. Got {}.'
                        .format(type(num)))
    if re.compile('^\s*\d+\s*$').search(num):
        return int(num)
    if re.compile('^\s*(\d*\.\d+)|(\d+\.\d*)\s*$').search(num):
        return float(num)
    raise ValueError('num is not a number. Got {}.'.format(num)) # optional

正規表現パターンに関する注記

^      beginning of string
$      end of string
\s*    none or more spaces
\d+    one or many digits
\d*    none or many digits
\.     literal dot
|      or

テスト

print(parse_str('1'))
print(parse_str('999'))
print(parse_str('1.2'))
print(parse_str('.3'))
print(parse_str('4.'))
print(parse_str('12.34'))
print(parse_str('    0.5    '))
print(parse_str('XYZ'))

結果

1
999
1.2
0.3
4.0
12.34
0.5
ValueError: num is not a number. Got XYZ.
0
Yahya

2つのXMLドキュメントの違いを判断しようとしたときに、「1.0」が「1」に変換されるようにする場合を処理する必要がありました。だから私は私を助けるためにこの関数を書きました。また、問題の文字列リテラルが「True」または「False」の場合、他の解決策のいくつかは失敗すると思います。とにかく、この機能は私にとって非常にうまく機能します。それがあなたにも役立つことを願っています。

from ast import literal_eval

def convertString(s):
    '''
    This function will try to convert a string literal to a number or a bool
    such that '1.0' and '1' will both return 1.

    The point of this is to ensure that '1.0' and '1' return as int(1) and that
    'False' and 'True' are returned as bools not numbers.

    This is useful for generating text that may contain numbers for diff
    purposes.  For example you may want to dump two XML documents to text files
    then do a diff.  In this case you would want <blah value='1.0'/> to match
    <blah value='1'/>.

    The solution for me is to convert the 1.0 to 1 so that diff doesn't see a
    difference.

    If s doesn't evaluate to a literal then s will simply be returned UNLESS the
    literal is a float with no fractional part.  (i.e. 1.0 will become 1)

    If s evaluates to float or a float literal (i.e. '1.1') then a float will be
    returned if and only if the float has no fractional part.

    if s evaluates as a valid literal then the literal will be returned. (e.g.
    '1' will become 1 and 'False' will become False)
    '''


    if isinstance(s, str):
        # It's a string.  Does it represnt a literal?
        #
        try:
            val = literal_eval(s)
        except:
            # s doesn't represnt any sort of literal so no conversion will be
            # done.
            #
            val = s
    else:
        # It's already something other than a string
        #
        val = s

    ##
    # Is the float actually an int? (i.e. is the float 1.0 ?)
    #
    if isinstance(val, float):
        if val.is_integer(): 
            return int(val)

        # It really is a float
        return val

    return val

この関数の単体テストの出力は次のようになります。

convertString("1")=1; we expect 1
convertString("1.0")=1; we expect 1
convertString("1.1")=1.1; we expect 1.1
convertString("010")=8; we expect 8
convertString("0xDEADBEEF")=3735928559; we expect 3735928559
convertString("hello")="hello"; we expect "hello"
convertString("false")="false"; we expect "false"
convertString("true")="true"; we expect "true"
convertString("False")=False; we expect False
convertString("True")=True; we expect True
convertString(sri.gui3.xmlSamples.test_convertString.A)=sri.gui3.xmlSamples.test_convertString.A; we expect sri.gui3.xmlSamples.test_convertString.A
convertString(<function B at 0x7fd9e2f27ed8>)=<function B at 0x7fd9e2f27ed8>; we expect <function B at 0x7fd9e2f27ed8>
convertString(1)=1; we expect 1
convertString(1.0)=1; we expect 1
convertString(1.1)=1.1; we expect 1.1
convertString(3735928559)=3735928559; we expect 3735928559
convertString(False)=False; we expect False
convertString(True)=True; we expect True

ユニットテストコードは次のとおりです。

import unittest

# just  class for testing that the class gets returned unmolested.
#
class A: pass

# Just a function
#
def B(): pass

class Test(unittest.TestCase):


    def setUp(self):
        self.conversions = [
            # input      | expected
            ('1'         ,1         ),
            ('1.0'       ,1         ), # float with no fractional part
            ('1.1'       ,1.1       ),
            ('010'       ,8         ), # octal
            ('0xDEADBEEF',0xDEADBEEF), # hex
            ('hello'     ,'hello'   ),
            ('false'     ,'false'   ),
            ('true'      ,'true'    ),
            ('False'     ,False     ), # bool
            ('True'      ,True      ), # bool
            (A           ,A         ), # class
            (B           ,B         ), # function
            (1           ,1         ),
            (1.0         ,1         ), # float with no fractional part
            (1.1         ,1.1       ),
            (0xDEADBEEF  ,0xDEADBEEF),
            (False       ,False     ),
            (True        ,True      ),
        ]


    def testName(self):
        for s,expected in self.conversions:
            rval = convertString(s)
            print 'convertString({s})={rval}; we expect {expected}'.format(**locals())
            self.assertEqual(rval, expected)


if __name__ == "__main__":
    #import sys;sys.argv = ['', 'Test.testName']
    unittest.main()
0
shrewmouse
lineVal = ['1850', '-0.373', '-0.339', '-0.425']

lineVal2 = [ float(x) if re.search(r'\.',x) else int(x) for x in lineVal ]

LineVal2 output ==> [1850, -0.373, -0.339, -0.425]

私は新しい蜂です、私はそれを試しました、私のために働くようです。

0
Nalan P

eval()を使用した興味深い解決策を次に示します。注:evalの使用は非常に危険であり、実稼働環境やeval()がユーザー入力を受け取る可能性のある場所ではお勧めしません。これは学術的に興味深い答えだけだと考えてください。

def get_string_type(x):
    if type(x) != str:
        raise ValueError('Input must be a string!')
    try:
        string_type = type(eval(x))
    except NameError:
        string_type = str
    return string_type

Evalは文字列を生のコードとして扱うため、これはreplに入力できるすべてのタイプで機能します。例

>>> from decimal import Decimal
>>> my_test_string = 'Decimal(0.5)'
>>> type(my_test_string)
<class 'str'>
>>> get_string_type(my_test_string)
<class 'decimal.Decimal'>
0