Como posso analisar uma string para um float ou int?
-
22-08-2019 - |
Pergunta
Em Python, como posso analisar uma seqüência numérica como "545.2222"
ao seu correspondente valor float, 545.2222
? Ou analisar o "31"
string para um inteiro, 31
?
Eu só quero saber como analisar um flutuador str
a um float
, e (separadamente) um int str
a um int
.
Solução
>>> a = "545.2222"
>>> float(a)
545.22220000000004
>>> int(float(a))
545
Outras dicas
def num(s):
try:
return int(s)
except ValueError:
return float(s)
método de Python para verificar se uma string é um float:
def is_float(value):
try:
float(value)
return True
except:
return False
Um nome mais longo e mais precisas para esta função poderia ser: is_convertible_to_float(value)
O que é, e não é um flutuador em Python pode surpreendê-lo:
val is_float(val) Note
-------------------- ---------- --------------------------------
"" False Blank string
"127" True Passed string
True True Pure sweet Truth
"True" False Vile contemptible lie
False True So false it becomes true
"123.456" True Decimal
" -127 " True Spaces trimmed
"\t\n12\r\n" True whitespace ignored
"NaN" True Not a number
"NaNanananaBATMAN" False I am Batman
"-iNF" True Negative infinity
"123.E4" True Exponential notation
".1" True mantissa only
"1,234" False Commas gtfo
u'\x30' True Unicode is fine.
"NULL" False Null is not special
0x3fade True Hexadecimal
"6e7777777777777" True Shrunk to infinity
"1.797693e+308" True This is max value
"infinity" True Same as inf
"infinityandBEYOND" False Extra characters wreck it
"12.34.56" False Only one dot allowed
u'四' False Japanese '4' is not a float.
"#56" False Pound sign
"56%" False Percent of what?
"0E0" True Exponential, move dot 0 places
0**0 True 0___0 Exponentiation
"-5e-5" True Raise to a negative number
"+1e1" True Plus is OK with exponent
"+1e1^5" False Fancy exponent not interpreted
"+1e1.3" False No decimals in exponent
"-+1" False Make up your mind
"(1)" False Parenthesis is bad
Você acha que sabe o que os números são? Você não é tão bom como você pensa! Não grande surpresa.
Não use este código no software crítico de vida!
Catching amplas exceções desta forma, matando canários e devorando a exceção cria uma pequena chance de que um flutuador válida como corda vai retornar falso. A linha de float(...)
de código pode falhou por qualquer uma das mil razões que nada têm a ver com o conteúdo da string. Mas se você é software crítico de vida escrita em uma linguagem protótipo pato-digitando como Python, então você tem problemas muito maiores.
Este é outro método que merece ser mencionado aqui, ast.literal_eval :
Isto pode ser usado para avaliar com segurança strings contendo expressões Python de fontes não confiáveis ??sem a necessidade de analisar os valores de si mesmo.
Isto é, um cofre 'eval'
>>> import ast
>>> ast.literal_eval("545.2222")
545.2222
>>> ast.literal_eval("31")
31
float(x) if '.' in x else int(x)
Localização e vírgulas
Você deve considerar a possibilidade de vírgulas na representação de cadeia de um número, para casos como float("545,545.2222")
que lança uma exceção. Em vez disso, usar métodos em locale
para converter as cordas para números e interpretar vírgulas corretamente. O método locale.atof
convertidos para um flutuador em um passo uma vez que o local foi definido para a convenção numérica pretendida.
Exemplo 1 - United States convenções numéricas
Nos Estados Unidos e no Reino Unido, vírgulas pode ser usado como um separador de milhares. Neste exemplo com locale americano, a vírgula é tratada adequadamente como um separador:
>>> 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
>>>
Exemplo 2 - European convenções numéricas
Na maioria dos países do mundo , vírgulas são usadas para marcas decimais em vez de períodos. Neste exemplo com locale francês, a vírgula é tratada corretamente como uma marca decimal:
>>> import locale
>>> b = u'545,2222'
>>> locale.setlocale(locale.LC_ALL, 'fr_FR')
'fr_FR'
>>> locale.atof(b)
545.2222
O método locale.atoi
também está disponível, mas o argumento deve ser um inteiro.
Se você não são avessos a módulos de terceiros, você poderia verificar o fastnumbers módulo. Ele fornece uma função chamada fast_real que faz exatamente o que esta questão é pedindo e fá-lo mais rápido do que uma implementação puro-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
Usuários codelogic e harley estão corretos, mas tenha em mente se você souber a string é um número inteiro (por exemplo, 545) você pode chamar int ( "545" ) sem primeiro fundição para float.
Se as cordas estão em uma lista, você pode usar a função de mapa também.
>>> x = ["545.0", "545.6", "999.2"]
>>> map(float, x)
[545.0, 545.60000000000002, 999.20000000000005]
>>>
Ele só é bom se eles estão todos do mesmo tipo.
A pergunta parece um pouco velho. Mas deixe-me sugerir uma função, parseStr, o que faz algo semelhante, ou seja, os retornos inteiro ou bóia e se uma dada seqüência de caracteres ASCII não pode ser convertido em nenhum deles ele retorna intacto. O código é claro pode ser ajustado para fazer apenas o que você quer:
>>> 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'
Em Python, como posso analisar uma seqüência numérica como "545.2222" ao seu valor float correspondente, 542.2222? Ou analisar a cadeia "31" para um inteiro, 31? Eu só quero saber como analisar uma seqüência float para um float, e (separadamente) uma string int para um int.
É bom que você pedir para fazer estes separadamente. Se você está misturando-os, você pode estar se preparando para problemas mais tarde. A resposta é simples:
"545.2222"
a flutuar:
>>> float("545.2222")
545.2222
"31"
para um inteiro:
>>> int("31")
31
Outras conversões, ints de e para cordas e literais:
As conversões de várias bases, e você deve saber a base de antecedência (10 é o padrão). Nota você pode prefixar-los com o Python espera por suas literais (veja abaixo) ou remover o prefixo:
>>> int("0b11111", 2)
31
>>> int("11111", 2)
31
>>> int('0o37', 8)
31
>>> int('37', 8)
31
>>> int('0x1f', 16)
31
>>> int('1f', 16)
31
Se você não sabe a base de antecedência, mas você sabe que vai ter o prefixo correto, Python pode inferir isso para você se você passar 0
como base:
>>> int("0b11111", 0)
31
>>> int('0o37', 0)
31
>>> int('0x1f', 0)
31
literais de outras bases não-decimais (isto é, número inteiro)
Se a sua motivação é ter o seu próprio código claramente representam valores específicos codificados, no entanto, você pode não precisar de converter a partir das bases -. Você pode deixar Python fazer isso por você automaticamente com a sintaxe correta ??p>
Você pode usar os prefixos apropos para obter a conversão automática para inteiros com o seguintes literais . Estes são válidos para Python 2 e 3:
Binário, prefixo 0b
>>> 0b11111
31
Octal, prefixo 0o
>>> 0o37
31
hexadecimal, prefixo 0x
>>> 0x1f
31
Isto pode ser útil ao descrever bandeiras binários, permissões de arquivo em código, ou valores hexadecimais para as cores - por exemplo, observar sem aspas:
>>> 0b10101 # binary flags
21
>>> 0o755 # read, write, execute perms for owner, read & ex for group & others
493
>>> 0xffffff # the color, white, max values for red, green, and blue
16777215
Fazendo ambíguas Python 2 octals compatíveis com o Python 3
Se você ver um número inteiro que começa com um 0, em Python 2, este é (reprovado) octal sintaxe.
>>> 037
31
É ruim porque parece que o valor deve ser 37
. Assim, em Python 3, que agora levanta uma SyntaxError
:
>>> 037
File "<stdin>", line 1
037
^
SyntaxError: invalid token
Converta seus Python 2 octals para octals que o trabalho em ambos os 2 e 3 com o prefixo 0o
:
>>> 0o37
31
float("545.2222")
e int(float("545.2222"))
O YAML analisador pode ajudar você a descobrir que tipo de dados a cadeia é. Use yaml.load()
, e então você pode usar type(result)
de teste para o tipo:
>>> 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'>
Eu uso essa função para que
import ast
def parse_str(s):
try:
return ast.literal_eval(str(s))
except:
return
Ele irá converter a string para o seu tipo
value = parse_str('1') # Returns Integer
value = parse_str('1.5') # Returns Float
def get_int_or_float(v):
number_as_float = float(v)
number_as_int = int(number_as_float)
return number_as_int if number_as_float == number_as_int else number_as_float
def num(s):
"""num(s)
num(3),num(3.7)-->3
num('3')-->3, num('3.7')-->3.7
num('3,700')-->ValueError
num('3a'),num('a3'),-->ValueError
num('3e4') --> 30000.0
"""
try:
return int(s)
except ValueError:
try:
return float(s)
except ValueError:
raise ValueError('argument is not a string of number')
Você precisa levar em conta o arredondamento para fazer isso corretamente.
i. int (5,1) => 5 int (5,6) => 5 - errado, deve ser de 6 por isso fazemos int (5,6 + 0,5) => 6
def convert(n):
try:
return int(n)
except ValueError:
return float(n + 0.5)
Estou surpreso que ninguém mencionou regex porque às vezes string deve ser preparado e normalizado antes de lançar para o número
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
uso:
parseNumber('13,345')
> 13345.0
parseNumber('- 123 000')
> -123000.0
parseNumber('99999\n')
> 99999.0
E, a propósito, algo para verificar se você tem um número:
import numbers
def is_number(value):
return isinstance(value, numbers.Number)
# will work with int, float, long, Decimal
Para typecast em python usar os funtions construtor do tipo, passando a cadeia (ou qualquer valor que você está tentando elenco) como parâmetro.
Por exemplo:
>>>float("23.333")
23.333
Nos bastidores, python está chamando o método objetos __float__
, que deve retornar uma representação flutuador do parâmetro. Isto é especialmente poderoso, como você pode definir seus próprios tipos (usando classes) com um método __float__
para que ele possa ser escalado em um flutuador usando float (myobject).
Esta é uma versão corrigida de https://stackoverflow.com/a/33017514/5973334
Esta tentará analisar uma string e retornar tanto int
ou float
dependendo do que a string representa.
Pode ascensão analisar exceções ou ter algum comportamento inesperado .
def get_int_or_float(v):
number_as_float = float(v)
number_as_int = int(number_as_float)
return number_as_int if number_as_float == number_as_int else
number_as_float
Use:
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()
Esta é a maneira mais Pythonic eu poderia vir acima com.
Use:
>>> str_float = "545.2222"
>>> float(str_float)
545.2222
>>> type(_) # Check its type
<type 'float'>
>>> str_int = "31"
>>> int(str_int)
31
>>> type(_) # Check its type
<type 'int'>
Esta é uma função que irá converter qualquer object
(não apenas str
) para int
ou float
, com base em se a cadeia real fornecido se parece com int
ou float
. Além disso, se é um objeto que tem ambos os métodos __float
e __int__
, o padrão é usar __float__
def conv_to_num(x, num_type='asis'):
'''Converts an object to a number if possible.
num_type: int, float, 'asis'
Defaults to floating point in case of ambiguity.
'''
import numbers
is_num, is_str, is_other = [False]*3
if isinstance(x, numbers.Number):
is_num = True
elif isinstance(x, str):
is_str = True
is_other = not any([is_num, is_str])
if is_num:
res = x
elif is_str:
is_float, is_int, is_char = [False]*3
try:
res = float(x)
if '.' in x:
is_float = True
else:
is_int = True
except ValueError:
res = x
is_char = True
else:
if num_type == 'asis':
funcs = [int, float]
else:
funcs = [num_type]
for func in funcs:
try:
res = func(x)
break
except TypeError:
continue
else:
res = x
Aqui está uma outra interpretação da sua pergunta (dica: é vaga). É possível que você está procurando algo parecido com isto:
def parseIntOrFloat( aString ):
return eval( aString )
Funciona assim ...
>>> parseIntOrFloat("545.2222")
545.22220000000004
>>> parseIntOrFloat("545")
545
Teoricamente, há uma vulnerabilidade de injeção. A string poderia, por exemplo, ser "import os; os.abort()"
. Sem qualquer fundo em que a cadeia vem, no entanto, a possibilidade é especulação teórica. Desde a pergunta é vaga, não é de todo claro se esta vulnerabilidade realmente existe ou não.