繁体   English   中英

Python, 判断一个字符串是应该转换成Int还是Float

[英]Python, Determine if a string should be converted into Int or Float

我想将字符串转换为最严格的数据类型:int 或 float。

我有两个字符串:

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

我如何确定 value1 应该是 Float 而 value2 应该是 Python 中的 Integer?

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

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

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())
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")

当我试图确定两个 XML 文档之间的差异时,我不得不处理确保将“1.0”转换为“1”的情况。 所以我写了这个函数来帮助我。 我还认为,当所讨论的字符串文字为“真”或“假”时,其他一些解决方案将失败。 无论如何,这个功能对我来说效果很好。 我希望它也能帮助你。

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()

另一种方法是使用这样的正则表达式:

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.
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]

我是新蜜蜂,我试过了,似乎对我有用。

短 function 的示例:返回字符串的数字类型(float 或 int),对于非数字字符串,返回 str 类型。

def numeric_type_of_string(string: str):
    if string.isnumeric():
        return int
    try:
        val = float(string)
        return int if val == int(val) else float
    except (TypeError, ValueError):
        return str

如果您直接想要转换后的值,只需修改返回值:

def string_to_numeric_if_possible(string: str):
    if string.isnumeric():
        return int(string)
    try:
        val = float(string)
        return int(val) if val == int(val) else val
    except (TypeError, ValueError):
        return string

这是一个使用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'>

我开始认为该请求是将存储为字符串的数字转换为 wither an or ,以最紧密的数据类型为准。 以下函数满足请求(但不检查输入是否为有效值,即数字而非字母字符)。

str_to_float_or_int()将存储为字符串的数字转换为<float><int> 尽管所有整数都可以是浮点数,但会尽可能返回<int>以满足“转换为最严格的数据类型”标准,如下所示:

  • 输入 = 一个整数。
  • 输入 = 尾数为 0 ('1.0') 的特征
  • 输入 = 没有尾数的特征 ('1.')

此技术使用str.isdecimal()确定字符串是否为值(与空值)和<str>.split(".")方法将字符串值(候选编号)解析为两部分:

  1. 整数 = 小数点前的数字
  2. 尾数 = 小数点后的数字

内置的<str>.split(".")方法返回一个列表。 在这种情况下,列表的格式如下: [integer, mantissa]

注意:从技术上讲,此处使用的术语“整数”实际上是指“特征”。 我使用“整数”是因为它的字符较少,因此更易于在编码中使用。

def str_to_float_or_int(value_str, ShowExtended=False):
    # Convert a number stored as a string to a <float> or an <int> 
    # whichever is the "tightest" data type. 

    # Default condition is that the number is a <float>
    isfloat = True
    value = float(value_str)
    numberParsed = value_str.split(".")
    if len(numberParsed) > 1:
        integer = numberParsed[0]
        mantissa = numberParsed[1]
        if integer.isdecimal() and mantissa.isdecimal():
            if int(mantissa) == 0:
                # value is an integer; mantissa is 0
                isfloat = False
                value = int(integer)
            elif integer.isdecimal():
                # value is an integer because a value is only
                # returned for 'integer' variable by .split(), 
                # the returned mantissa value is null.
                isfloat = False
                value = int(integer)
        else:
            # value is an integer because .split() returned
            # a single value list.
            isfloat = False
            value = int(value_str)
        if ShowExtended:
            print("testValue: " + value_str + " | splits into: ", 
                   numberParsed,"\n value: ", value)
            if isfloat:
                print("It's a <float> (;o)\n")
            else:
                print("It's an <int> {:o)~\n")
        return value

从控制台运行脚本以测试 str_to_float_or_int()


testValues = ["0.80", "1.00", "5", ".1", "4."]
print("\n-----------------------------------------------\n" +
        "| Testcase:  ", testValues, " |\n" +
        "-----------------------------------------------")
for number in testValues:
    str_to_float_or_int(number, ShowExtended=True)

输出结果(从控制台复制)


>   ---------------------------------------------------
>   |  Testcase:   ['0.80', '1.00', '5', '.1', '4.']  |
>   ---------------------------------------------------
>   testValue: 0.80 | splits into:  ['0', '80']
>   value:  0.8
>   It's a <float> (;o)
>   
>   testValue: 1.00 | splits into:  ['1', '00']
>   value:  1
>   It's an <int> {:o)~
>   
>   testValue: 5 | splits into:  ['5']
>   value:  5
>   It's an <int> {:o)~
>   
>   testValue: .1 | splits into:  ['', '1']
>   value:  0.1
>   It's a <float> (;o)
>
>   testValue: 4. | splits into:  ['4', '']
>   value:  4
>   It's an <int> {:o)~

这个简单的函数可以解决问题,您只需要“解决方案”代码块。

intOrfloat.py:

import sys
def NumberType(argv):
    Number = argv[1]
    try:
        float(Number)   # Exception if not a number
        ################ Solution ################
        if '.' not in Number:
            return '%s is Integer'%(Number)
        if int(Number.split('.')[1]) > 0:
            return '%s is Float'%(Number)
        else:
            return '%s is Integer'%(Number)
        ##########################################
    except Exception as e:
        return '%s is Text...'%(Number)
if __name__ == '__main__':
    print(NumberType(sys.argv))

测试:

>python intOrfloat.py 0.80
0.80 is Float

>python intOrfloat.py 1.00
1.00 is Integer

>python intOrfloat.py 9999999999999999
9999999999999999 is Integer

因此,无需担心整数的大小。

'.' not in Number              # number without decimal must be an integer
Number.split('.')              # split into [integer String, decimal String]
Number.split('.')[1]           # get decimal String
int(Number.split('.')[1])      # convert it into decimal Number
int(Number.split('.')[1]) > 0  # decimal Number > 0 = Float; Otherwise, Integer

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM