[英]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>
以滿足“轉換為最嚴格的數據類型”標准,如下所示:
此技術使用str.isdecimal()
確定字符串是否為值(與空值)和<str>.split(".")
方法將字符串值(候選編號)解析為兩部分:
內置的<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.