Como é que eu analiso um texto para um flutuador ou int em Python?
em Python, como posso processar uma cadeia numérica como "545.2222"
para o seu valor flutuante correspondente, 542.2222
? Ou analisar o texto "31"
para um inteiro, 31
?
string
a float
, e (separadamente) a int string
a um.
23 answers
>>> a = "545.2222"
>>> float(a)
545.22220000000004
>>> int(float(a))
545
def num(s):
try:
return int(s)
except ValueError:
return float(s)
Método Python para verificar se um texto é um 'float':
def is_float(value):
try:
float(value)
return True
except:
return False
Um nome mais longo e mais preciso para esta função pode ser: is_convertible_to_float(value)
O que é, e não é um flutuador em Python pode surpreender-te:
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
Achas que sabes o que são números? Não és tão bom como pensas! Não é grande surpresa.
Isto é, uma avaliação segura.Isto pode ser usado para avaliar de forma segura as cadeias de caracteres que contêm expressões em Python de fontes não confiáveis sem a necessidade de analisar os próprios valores.
>>> 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, use métodos em locale
para converter as cadeias em números e interpretar vírgulas corretamente. O método locale.atof
converte-se para um flutuador numa etapa, uma vez que a configuração local tenha sido definida para a Convenção de números desejada.
Exemplo 1 -- Convenções de números dos Estados Unidos
Nos Estados Unidos e no Reino Unido, vírgulas podem ser usadas como separador de milhares. Neste exemplo com o American locale, a vírgula é tratada corretamente 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 -- convenções europeias sobre números
Na maioria dos países do mundo , as vírgulas são usadas para marcas decimais em vez de períodos. Neste exemplo com o local francês, a vírgula é correctamente tratada 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 número inteiro.
Os utilizadores codelogic e harley estão correctos, mas tenha em mente que, se souber que a cadeia de caracteres é um inteiro (por exemplo, 545), pode chamar-se int("545") sem primeiro elenco para flutuar.
Se as suas cadeias de caracteres estão numa lista, também pode usar a função do mapa.
>>> x = ["545.0", "545.6", "999.2"]
>>> map(float, x)
[545.0, 545.60000000000002, 999.20000000000005]
>>>
Só é bom se forem todos do mesmo tipo.
Se não for avesso a módulos de terceiros, pode verificar o Módulo fastnumbers. Ele fornece uma função chamada fast_real que faz exatamente o que esta pergunta está pedindo e faz isso mais rápido do que uma implementação em Python puro:
>>> 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
É bom que peças para fazer isto separadamente. Se você estiver misturando-os, você pode estar se preparando para problemas mais tarde. A resposta simples é:Em Python, como posso processar uma string numérica como "545.2222" para seu valor float correspondente, 542.2222? Ou analisar a string "31" para um inteiro, 31? Eu só quero saber como processar um string flutuante para um float, e (separadamente) um string int para um int.
"545.2222"
para vírgula flutuante:
>>> float("545.2222")
545.2222
"31"
para um número inteiro:
>>> int("31")
31
Outras conversões, entradas de e para cadeias de caracteres e literais:
Conversões de várias bases, e você deve saber a base com antecedência (10 é o padrão). Lembre-se que poderá prefixá-los com o que o Python espera para os seus literais (veja em baixo) 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 conhece a base com antecedência, mas você sabe que eles terão o prefixo correto, Python pode inferir isso para você se você passe 0
como base:
>>> int("0b11111", 0)
31
>>> int('0o37', 0)
31
>>> int('0x1f', 0)
31
Literais não decimais (isto é, inteiros) de outras Bases
Se a sua motivação é ter o seu próprio código representa claramente valores específicos codificados, no entanto, pode não precisar de converter a partir das bases - pode deixar o Python fazê-lo automaticamente com a sintaxe correcta.
Pode usar os prefixos apropos para obter a conversão automática para inteiros com os seguintes literais. Estes são válidos para o 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 as opções binárias, as permissões de ficheiros em código ou os valores do Hexadecimal para as cores - por exemplo, note no quotes:
>>> 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
Tornando os octais Python 2 ambíguos compatíveis com o Python 3
Se vir um inteiro que começa com um 0, no Python 2, esta é a sintaxe octal (obsoleta).
>>> 037
31
É mau porque ... parece que o valor deve ser 37
. Então, no Python 3, ele agora levanta um SyntaxError
:
>>> 037
File "<stdin>", line 1
037
^
SyntaxError: invalid token
Converta os seus octais Python 2 para octais que funcionam tanto em 2 como em 3 com o prefixo 0o
:
>>> 0o37
31
>>> 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'
float("545.2222")
e int(float("545.2222"))
O analisador YAML pode ajudá-lo a descobrir que tipo de dados é o seu texto. Use yaml.load()
, e então você pode usar type(result)
para testar 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'>
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
Uso Esta função para isso
import ast
def parse_str(s):
try:
return ast.literal_eval(str(s))
except:
return
Irá converter a cadeia de caracteres para o seu tipo
value = parse_str('1') # Returns Integer
value = parse_str('1.5') # Returns Float
Tem de ter em conta os arredondamentos para fazer isto correctamente.
I. e. int (5.1) = > 5 int (5.6) = > 5 -- wrong, should be 6 so we do int(5.6 + 0.5) => 6
def convert(n):
try:
return int(n)
except ValueError:
return float(n + 0.5)
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')
Esta é uma versão corrigida de https://stackoverflow.com/a/33017514/5973334
Isto irá tentar processar uma cadeia de caracteres e retornar int
ou float
dependendo do que a cadeia de caracteres representa.
Pode aumentar as excepções de análise 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
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
Utilização:
parseNumber('13,345')
> 13345.0
parseNumber('- 123 000')
> -123000.0
parseNumber('99999\n')
> 99999.0
E já agora, algo para verificar, tem um número:
import numbers
def is_number(value):
return isinstance(value, numbers.Number)
# will work with int, float, long, Decimal
Python tem esta grande flexibilidade de análise em uma linha.
str = "545.2222"
print ("int: ", + int(float(a)))
print ("float: ", +(float(a)))
Para escrever em python use as funções do construtor do tipo, passando o texto (ou qualquer que seja o valor que você está tentando lançar) como um parâmetro.
Por exemplo:
>>>float("23.333")
23.333
Nos bastidores, o python está a chamar o método dos objectos __float__
, que deverá devolver uma representação flutuante do parâmetro. Isto é especialmente poderoso, uma vez que você pode definir os seus próprios tipos (usando classes) com um método __float__
de modo que ele possa ser rodado para um carro flutuante usando o float(myobject).
Utilizar:
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 Pitónica que consegui arranjar.
Utilizar:
>>> 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'>
def parseIntOrFloat( aString ):
return eval( aString )
Funciona assim...
>>> parseIntOrFloat("545.2222")
545.22220000000004
>>> parseIntOrFloat("545")
545
Teoricamente, há uma vulnerabilidade à injecção. A string poderia, por exemplo, ser
"import os; os.abort()"
. Sem qualquer fundo sobre de onde a corda vem, entretanto, a possibilidade é especulação teórica. Uma vez que a pergunta é vaga, não é claro se essa vulnerabilidade realmente existe ou nao.