简体   繁体   English

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

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

I want to convert a string to the tightest possible datatype: int or float.我想将字符串转换为最严格的数据类型:int 或 float。

I have two strings:我有两个字符串:

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

How I can determine that value1 should be Float and value2 should be Integer in Python?我如何确定 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 objects have anis_integer method : 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")

I had to handle the case of ensuring that '1.0' gets converted to '1' when I was trying to determine the differences between two XML documents.当我试图确定两个 XML 文档之间的差异时,我不得不处理确保将“1.0”转换为“1”的情况。 So I wrote this function to help me.所以我写了这个函数来帮助我。 I also think that some of the other solutions will fail when the string literal in question is 'True' or 'False'.我还认为,当所讨论的字符串文字为“真”或“假”时,其他一些解决方案将失败。 At any rate this function works very well for me.无论如何,这个功能对我来说效果很好。 I hope that it will help you too.我希望它也能帮助你。

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

The output of the unit test of this function produces:此函数的单元测试的输出产生:

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

The unit test code follows:单元测试代码如下:

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

Another way to do this, is by using regex like this:另一种方法是使用这样的正则表达式:

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

Notes on Regex Pattern正则表达式模式的注意事项

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

Test测试

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

Result结果

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]

I'm new bee, I tried it, seem to work for me.我是新蜜蜂,我试过了,似乎对我有用。

Example for a short function: Returns the numeric type of a string (float or int), for non-numeric strings the str type is returned.短 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

In case you directly want the converted value simply modify the return value:如果您直接想要转换后的值,只需修改返回值:

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

Here's an interesting solution using eval() .这是一个使用eval()的有趣解决方案。 Note: using eval is highly dangerous and not recommended in production environments or anywhere that eval() might receive user input!注意:使用 eval 是非常危险的,不建议在生产环境或eval()可能接收用户输入的任何地方使用! Consider this an academically interesting answer only.仅将此视为学术上有趣的答案。

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

Since Eval treats the string as raw code, this works for any type you can enter into a repl.由于 Eval 将字符串视为原始代码,因此这适用于您可以输入到 repl 中的任何类型。 Example例子

>>> 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'>

I got to thinking that the request was to convert a number stored as a string to wither an or , whichever is the tightest data type.我开始认为该请求是将存储为字符串的数字转换为 wither an or ,以最紧密的数据类型为准。 The following function fulfills the request (but does not check if the input is a valid value, ie a number an not alpha characters).以下函数满足请求(但不检查输入是否为有效值,即数字而非字母字符)。

The str_to_float_or_int() converts a number stored as a string to a <float> or an <int> . str_to_float_or_int()将存储为字符串的数字转换为<float><int> Although all integers can be floats, an <int> is returned wherever possible to meet the "convert to tightest data type" criteria as when:尽管所有整数都可以是浮点数,但会尽可能返回<int>以满足“转换为最严格的数据类型”标准,如下所示:

  • input = a whole number.输入 = 一个整数。
  • input = a characteristic with a 0 mantissa ('1.0')输入 = 尾数为 0 ('1.0') 的特征
  • input = a characteristic without a mantissa ('1.')输入 = 没有尾数的特征 ('1.')

This technique uses the str.isdecimal() to determine if the string is a value (vs. a null) and the <str>.split(".") method to parse the string value (candidate number) into two parts:此技术使用str.isdecimal()确定字符串是否为值(与空值)和<str>.split(".")方法将字符串值(候选编号)解析为两部分:

  1. integer = number before the decimal整数 = 小数点前的数字
  2. Mantissa = number after the decimal place尾数 = 小数点后的数字

The built-in <str>.split(".") method returns a list.内置的<str>.split(".")方法返回一个列表。 In this case, list is of the following format: [integer, mantissa]在这种情况下,列表的格式如下: [integer, mantissa]

Note: Technically, the use of the term 'integer' here really refers to the 'characteristic'.注意:从技术上讲,此处使用的术语“整数”实际上是指“特征”。 I used 'integer' because it has less characters and thus easier to use in coding.我使用“整数”是因为它的字符较少,因此更易于在编码中使用。

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

Run Script from the Console to test str_to_float_or_int()从控制台运行脚本以测试 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)

Output Results (copied from the console)输出结果(从控制台复制)


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

this simple function can tackle the problem, you just need the "Solution" block of code.这个简单的函数可以解决问题,您只需要“解决方案”代码块。

intOrfloat.py: 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))

tests:测试:

>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

So, no need to worry about the size of integer number.因此,无需担心整数的大小。

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