Jak parsować ciąg na zmiennoprzecinkowe lub int?


2249

W Pythonie, w jaki sposób można analizować ciąg liczbowy jak "545.2222"do odpowiadającej jej wartości float 545.2222? Lub parsować ciąg "31"do liczby całkowitej 31?

Chcę tylko wiedzieć, jak parsować zmiennoprzecinkowe str do floati (osobno) int str do int.


7
Zasadniczo, jeśli masz obiekt w Pythonie i chcesz przekonwertować go na ten typ obiektu, wywołaj type(my_object)go. Wynik można zwykle wywołać jako funkcję konwersji. Na przykład type(100)powoduje int, że możesz zadzwonić, int(my_object)aby spróbować przekonwertować my_objectna liczbę całkowitą. To nie zawsze działa, ale jest dobrym „pierwszym odgadnięciem” podczas kodowania.
robertlayton

int(x) if int(x) == float(x) else float(x)
tcpaiva

Odpowiedzi:


2621
>>> a = "545.2222"
>>> float(a)
545.22220000000004
>>> int(float(a))
545

8
zastanawiam się, dlaczego na końcu jest „04”? dlaczego nie po prostu „00”? także moja obecna wersja Pythona nie ma „04”.
Mangat Rai Modi

54
@MangatRaiModi Liczby zmiennoprzecinkowe są z natury niedoskonałe do reprezentowania miejsc po przecinku. Aby uzyskać więcej informacji, zobacz stackoverflow.com/q/21895756/931277
dokkaebi

19
dlaczego nie po prostu, int(a)ale int(float(a))?
idclev 463035818

24
int(a)spowoduje błąd, że ciąg nie jest prawidłową liczbą całkowitą: ValueError: invalid literal for int() with base 10: '545.222'ale konwersja z liczby zmiennoprzecinkowej na liczbę całkowitą jest obsługiwaną konwersją.
David Parks,

4
Powinieneś sobie poradzić, ValueErrorjeśli chcesz być bezpieczny
Joe Bobson,

515
def num(s):
    try:
        return int(s)
    except ValueError:
        return float(s)

81
niejawne mieszanie liczb zmiennoprzecinkowych / liczb całkowitych może prowadzić do subtelnych błędów z powodu możliwej utraty precyzji podczas pracy z liczbami zmiennoprzecinkowymi lub różnych wyników dla /operatora liczb zmiennoprzecinkowych / liczb całkowitych. W zależności od kontekstu może być wskazane zwrócenie int lub float, a nie obu.
jfs

14
@JFSebastian Masz całkowitą rację, ale są chwile, kiedy chcesz, aby dane wejściowe decydowały, który z nich będzie. Pozwól, aby dane wejściowe decydowały, który z nich może ładnie pracować przy pisaniu kaczym.
TimothyAWiseman

4
Możesz zagnieździć inny, tryaby zgłosić wyjątek, gdy nie można go zamienić na zmiennoprzecinkowy.
iBug

2
Nie działa zs = u'\u0000'
Matt Hancock

1
@iBug Dobry pomysł! Polecam wrzucenie ValueErrorodpowiedniego except: P
marcelm

511

Metoda Pythona, aby sprawdzić, czy ciąg jest liczbą zmiennoprzecinkową:

def is_float(value):
  try:
    float(value)
    return True
  except:
    return False

Dłuższą i dokładniejszą nazwą tej funkcji może być: is_convertible_to_float(value)

Co jest, a nie jest zmiennoprzecinkowe w Pythonie, może cię zaskoczyć:

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

Myślisz, że wiesz, jakie są liczby? Nie jesteś tak dobry, jak myślisz! Nie wielka niespodzianka.

Nie używaj tego kodu w oprogramowaniu krytycznym dla życia!

Łapanie w ten sposób szerokich wyjątków, zabijanie kanarków i pożeranie wyjątku stwarza niewielką szansę, że prawidłowy zmiennoprzecinkowy ciąg znaków zwróci false. float(...)Linia kodu może nie powiodła się dla żadnego z tysiąca powodów, które nie mają nic wspólnego z treścią napisu. Ale jeśli piszesz krytyczne oprogramowanie w kaczym prototypowym języku, takim jak Python, masz znacznie większe problemy.


1
Tak więc prawda staje się 1, to znaczy odziedziczyłem po C ++, myślę
FindOutIslamNow

6
Opublikowałem tę odpowiedź w 2014 roku. Ten UTF-8glif dla Chińczyków 4zmieniał się przez lata, w zależności od tego, jak programiści Stackoverflow zmieniają schemat kodowania znaków po zastosowaniu pakietu narzędzi Microsoft. Z ciekawością patrzy się, jak zmienia się z biegiem lat, gdy nowe schematy konwersji potwierdzają swoje nowe ideologie. Ale tak, każdy UTF-8glif dla wschodnich liczb orientalnych nie jest pływakiem Pythona. Bazinga.
Eric Leschinski,

4
jak można to tak pozytywnie oceniać, z tak szerokim wyjątkiem?
E.Serra

Wszystko ze spacjami pomiędzy nie może być przekształcone, jak "- 12.3"i"45 e6"
Simon

1
Ten wyjątek, z wyjątkiem klauzuli, powinien być ograniczony doTypeError, ValueError
wim

131

Jest to kolejna metoda, o której warto wspomnieć tutaj, ast.literal_eval :

Można to wykorzystać do bezpiecznej oceny ciągów zawierających wyrażenia Python z niezaufanych źródeł bez konieczności samodzielnego analizowania wartości.

To znaczy, bezpieczna „ewaluacja”

>>> import ast
>>> ast.literal_eval("545.2222")
545.2222
>>> ast.literal_eval("31")
31

11
to nie jest dobre rozwiązanie problemu. Działa dobrze w Pythonie 2, ale w Pythonie 3 dzieje się tak: python >>> import ast >>> ast.literal_eval('1-800-555-1212') -2566 >>> Aby wyjaśnić, dlaczego jest to problem, jeśli chcesz, aby pozostawiał numery telefonów w spokoju i nie zakładał, że są wyrażeniami matematycznymi, to podejście nie jest dla Ciebie.
royce3

6
@ royce3 Tak, to dobra uwaga i użytkownicy powinni się wystrzegać. Zachowanie zostało pierwotnie zmodyfikowane w celu rozwiązania niektórych problemów z analizowaniem złożonych literałów. Prawdopodobnie jest to błąd ast.literal_eval, który został tutaj omówiony .
wim

79
float(x) if '.' in x else int(x)

21
Uwaga: zachowaj ostrożność w przypadku pieniędzy przekazywanych jako ciągi znaków, ponieważ niektóre kraje używają „,” jako separatorów dziesiętnych
Ben G

127
@Emile: Nie nazwałbym „2e-3” „ekstremalnym przypadkiem”. Ta odpowiedź jest po prostu zepsuta.
jchl

14
@BenG NIE manipuluj pieniędzmi jak float. To prosi o kłopoty. Użyj dziesiętnych do pieniędzy! (Ale twój komentarz na temat „,” jest nadal ważny i ważny)
ToolmakerSteve,

4
Nie zapominaj, że „not a number” (NaN) i +/- nieskończoność są również prawidłowymi wartościami zmiennoprzecinkowymi. float("nan")Jest to więc całkowicie poprawna wartość zmiennoprzecinkowa, której powyższa odpowiedź w ogóle nie złapie
Ronny Andersson

2
Łatwo łamliwy przez adres IP - 192.168.0.1; lub"This is not a good approach. :)"
Todor Minakov

69

Lokalizacja i przecinki

Należy wziąć pod uwagę możliwość przecinków w reprezentacji ciągu liczby, w przypadkach takich jak float("545,545.2222")który zgłasza wyjątek. Zamiast tego użyj metod w, localeaby przekonwertować ciągi na liczby i poprawnie interpretować przecinki. Te locale.atofmetody przekształca się w obrocie w jednym etapie raz na lokalizacji jest ustawiony w pożądanym Konwencji numerycznej.

Przykład 1 - Konwencje liczbowe w Stanach Zjednoczonych

W Stanach Zjednoczonych i Wielkiej Brytanii przecinki mogą być używane jako separator tysięcy. W tym przykładzie z amerykańskimi ustawieniami narodowymi przecinek jest poprawnie traktowany jako separator:

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

Przykład 2 - Europejskie konwencje liczbowe

W większości krajów świata przecinki są używane jako znaki dziesiętne zamiast kropek. W tym przykładzie z ustawieniami francuskimi przecinek jest poprawnie obsługiwany jako znak dziesiętny:

>>> import locale
>>> b = u'545,2222'
>>> locale.setlocale(locale.LC_ALL, 'fr_FR')
'fr_FR'
>>> locale.atof(b)
545.2222

Metoda locale.atoijest również dostępna, ale argumentem powinna być liczba całkowita.


Wydaje się, że jest to idealne rozwiązanie, gdy wiesz, czy liczba zmiennoprzecinkowa lub liczba całkowita powinna zostać zwrócona, ale jak możesz to zrobić, aby zwrócić wartość całkowitą tylko wtedy, gdy wartość int została przekazana? Na przykład x = '1'; locale.atof(x)zwraca, 1.0gdy naprawdę chcę 1.
user5359531,

Przy użyciu metody Dino wydaje mi się, że odpowiedzią byłoby użycie czegoś takiego:locale.atof(x) if locale.localeconv().get('decimal_point') in x else locale.atoi(x)
user5359531

locale.atoilocale.atof
Poleciłbym

27

Jeśli nie jesteś przeciwny modułom innych firm, możesz sprawdzić moduł fastnumbers . Zapewnia funkcję o nazwie fast_real, która robi dokładnie to, o co pyta to pytanie i działa szybciej niż implementacja czysto 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

24

Użytkownicy codelogic i harley są poprawni, ale pamiętaj, jeśli wiesz, że ciąg jest liczbą całkowitą (na przykład 545), możesz wywołać int („545”) bez pierwszego rzutowania na zmiennoprzecinkowe.

Jeśli twoje ciągi znajdują się na liście, możesz również użyć funkcji mapy.

>>> x = ["545.0", "545.6", "999.2"]
>>> map(float, x)
[545.0, 545.60000000000002, 999.20000000000005]
>>>

Dobrze jest, jeśli wszystkie są tego samego typu.


21

W Pythonie, jak mogę przeanalizować ciąg liczbowy, taki jak „545.2222”, z odpowiadającą mu wartością zmiennoprzecinkową, 542.2222? Lub parsować ciąg „31” na liczbę całkowitą, 31? Chcę tylko wiedzieć, jak parsować ciąg zmiennoprzecinkowy na zmiennoprzecinkowy i (osobno) ciąg int na int.

Dobrze, że poprosisz o zrobienie tego osobno. Jeśli je miksujesz, być może będziesz się później przygotowywał na problemy. Prosta odpowiedź brzmi:

"545.2222" unosić:

>>> float("545.2222")
545.2222

"31" do liczby całkowitej:

>>> int("31")
31

Inne konwersje, ints do iz ciągów znaków i literałów:

Konwersje z różnych baz i powinieneś znać bazę z góry (domyślnie jest to 10). Pamiętaj, że możesz poprzedzić je tym, czego oczekuje Python od jego literałów (patrz poniżej) lub usunąć prefiks:

>>> int("0b11111", 2)
31
>>> int("11111", 2)
31
>>> int('0o37', 8)
31
>>> int('37', 8)
31
>>> int('0x1f', 16)
31
>>> int('1f', 16)
31

Jeśli nie znasz bazy z góry, ale wiesz, że będą miały poprawny przedrostek, Python może wywnioskować to, jeśli podasz 0jako podstawę:

>>> int("0b11111", 0)
31
>>> int('0o37', 0)
31
>>> int('0x1f', 0)
31

Literały nie dziesiętne (tj. Całkowite) z innych baz

Jeśli twoją motywacją jest posiadanie własnego kodu wyraźnie reprezentującego określone, zakodowane na stałe wartości, może nie być konieczne konwertowanie z baz - możesz pozwolić Pythonowi zrobić to automatycznie za pomocą właściwej składni.

Możesz użyć przedrostków apropos, aby uzyskać automatyczną konwersję na liczby całkowite o następujących literałach . Są one ważne dla Pythona 2 i 3:

Binarny, prefiks 0b

>>> 0b11111
31

Oktalowy, przedrostek 0o

>>> 0o37
31

Szesnastkowy, przedrostek 0x

>>> 0x1f
31

Może to być przydatne przy opisywaniu flag binarnych, uprawnień do plików w kodzie lub wartości szesnastkowych dla kolorów - na przykład nie zauważaj cudzysłowów:

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

Dostosowywanie dwuznacznych oktałów Python 2 do Python 3

Jeśli widzisz liczbę całkowitą rozpoczynającą się od 0, w Pythonie 2 jest to (przestarzała) składnia ósemkowa.

>>> 037
31

Jest źle, ponieważ wygląda na to, że wartość powinna być 37. W Pythonie 3 pojawia się teraz SyntaxError:

>>> 037
  File "<stdin>", line 1
    037
      ^
SyntaxError: invalid token

Konwertuj liczby ósemkowe w języku Python 2 na liczby ósemkowe, które działają zarówno w 2, jak i 3 z 0oprefiksem:

>>> 0o37
31

20

Pytanie wydaje się trochę stare. Ale pozwól, że zasugeruję funkcję, parseStr, która czyni coś podobnego, to znaczy zwraca liczbę całkowitą lub zmiennoprzecinkową, a jeśli dany ciąg ASCII nie może zostać przekonwertowany na żadną z nich, zwraca go nietknięty. Kod można oczywiście dostosować tak, aby robił tylko to, co chcesz:

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

8
1e3to liczba w pythonie, ale ciąg zgodny z twoim kodem.
Cees Timmerman,

16

float("545.2222") i int(float("545.2222"))


1
To da ci obiekt zmiennoprzecinkowy, jeśli twój łańcuch będzie miał „0” lub „0.0”, a nie liczbę całkowitą podaną dla innych prawidłowych liczb.
Brian,

14

Używam do tego tej funkcji

import ast

def parse_str(s):
   try:
      return ast.literal_eval(str(s))
   except:
      return

Przekształci ciąg na swój typ

value = parse_str('1')  # Returns Integer
value = parse_str('1.5')  # Returns Float

Należy pamiętać, że parse_str(' 1')(ze spacją) wróci None, nie 1.
musiphil

13

YAML parser może pomóc dowiedzieć się, co typ danych ciąg jest. Użyj yaml.load(), a następnie możesz użyć type(result)do przetestowania typu:

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

11
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

1
Dlaczego miałbyś podbijać w swojej exceptsekcji, jeśli nic tam nie robisz? float () podbije za ciebie.
Greg0ry

1
masz rację. Myślę, że skopiowałem i wkleiłem z funkcji, z której zgłaszałem szczególny wyjątek. edytuje. dzięki
Totoro,

1
Spróbuje to parsować ciąg i zwróci albo albo, intalbo w floatzależności od tego, co reprezentuje ciąg. Może pojawić się parsowanie wyjątków lub [mieć nieoczekiwane zachowanie] [1].
Kuzeko

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

6

Aby to zrobić poprawnie, należy wziąć pod uwagę zaokrąglenie.

Tj. Int (5.1) => 5 int (5.6) => 5 - źle, powinno być 6, więc robimy int (5.6 + 0.5) => 6

def convert(n):
    try:
        return int(n)
    except ValueError:
        return float(n + 0.5)

4
Słuszna uwaga. To powoduje inflację, więc Python 3 i inne współczesne języki używają zaokrąglania bankowego.
Cees Timmerman,

2
Ta odpowiedź jest niepoprawna (jak pierwotnie napisano). Zamazuje dwa przypadki inti float. I da wyjątek, gdy njest łańcuchem, zgodnie z życzeniem OP. Może masz na myśli: Kiedyint jest pożądany wynik, roundnależy zrobić konwersji PO unosić. Jeśli funkcja powinna ZAWSZE zwracać liczbę całkowitą, to nie potrzebujesz części wyjątkowej - cała treść funkcji może być int(round(float(input))). Jeśli funkcja zwraca int, jeśli to możliwe, w przeciwnym razie zmiennoprzecinkowe, oryginalne rozwiązanie javier jest poprawne!
ToolmakerSteve,

5

Dziwi mnie, że nikt nie wspominał o wyrażeniu regularnym, ponieważ czasami ciąg musi być przygotowany i znormalizowany przed rzutem na liczbę

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

stosowanie:

parseNumber('13,345')
> 13345.0

parseNumber('- 123 000')
> -123000.0

parseNumber('99999\n')
> 99999.0

a przy okazji, coś do zweryfikowania masz numer:

import numbers
def is_number(value):
    return isinstance(value, numbers.Number)
    # will work with int, float, long, Decimal

5

Aby typecast w Pythonie, użyj funkcji konstruktora typu, przekazując ciąg (lub dowolną wartość, którą próbujesz rzutować) jako parametr.

Na przykład:

>>>float("23.333")
   23.333

Za kulisami Python wywołuje __float__metodę object, która powinna zwrócić zmienną reprezentację parametru. Jest to szczególnie wydajne, ponieważ można definiować własne typy (za pomocą klas) za pomocą __float__metody, dzięki czemu można go rzutować na zmiennoprzecinkowe za pomocą zmiennoprzecinkowego (myobject).



2

Przekaż ciąg znaków do tej funkcji:

def string_to_number(str):
  if("." in str):
    try:
      res = float(str)
    except:
      res = str  
  elif(str.isdigit()):
    res = int(str)
  else:
    res = str
  return(res)

Zwróci int, float lub string w zależności od tego, co zostało przekazane.

ciąg znaków, który jest liczbą całkowitą

print(type(string_to_number("124")))
<class 'int'>

ciąg znaków, który jest liczbą zmiennoprzecinkową

print(type(string_to_number("12.4")))
<class 'float'>

ciąg, który jest ciągiem

print(type(string_to_number("hello")))
<class 'str'>

ciąg, który wygląda jak pływak

print(type(string_to_number("hel.lo")))
<class 'str'>

1

Posługiwać się:

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

To najbardziej pythoniczny sposób, jaki mogłem wymyślić.


Generator zatrzymuje się po pierwszej interpretacji float. try... catchblok powinien prawdopodobnie wewnątrz forpętli.
musiphil

1

Obsługuje wartości szesnastkowe, ósemkowe, binarne, dziesiętne i zmiennoprzecinkowe

To rozwiązanie poradzi sobie ze wszystkimi konwencjami ciągów liczb (wszystko, o czym wiem).

def to_number(n):
    ''' Convert any number representation to a number 
    This covers: float, decimal, hex, and octal numbers.
    '''

    try:
        return int(str(n), 0)
    except:
        try:
            # python 3 doesn't accept "010" as a valid octal.  You must use the
            # '0o' prefix
            return int('0o' + n, 0)
        except:
            return float(n)

Dane wyjściowe przypadku testowego ilustrują to, o czym mówię.

======================== CAPTURED OUTPUT =========================
to_number(3735928559)   = 3735928559 == 3735928559
to_number("0xFEEDFACE") = 4277009102 == 4277009102
to_number("0x0")        =          0 ==          0
to_number(100)          =        100 ==        100
to_number("42")         =         42 ==         42
to_number(8)            =          8 ==          8
to_number("0o20")       =         16 ==         16
to_number("020")        =         16 ==         16
to_number(3.14)         =       3.14 ==       3.14
to_number("2.72")       =       2.72 ==       2.72
to_number("1e3")        =     1000.0 ==       1000
to_number(0.001)        =      0.001 ==      0.001
to_number("0xA")        =         10 ==         10
to_number("012")        =         10 ==         10
to_number("0o12")       =         10 ==         10
to_number("0b01010")    =         10 ==         10
to_number("10")         =         10 ==         10
to_number("10.0")       =       10.0 ==         10
to_number("1e1")        =       10.0 ==         10

Oto test:

class test_to_number(unittest.TestCase):

    def test_hex(self):
        # All of the following should be converted to an integer
        #
        values = [

                 #          HEX
                 # ----------------------
                 # Input     |   Expected
                 # ----------------------
                (0xDEADBEEF  , 3735928559), # Hex
                ("0xFEEDFACE", 4277009102), # Hex
                ("0x0"       ,          0), # Hex

                 #        Decimals
                 # ----------------------
                 # Input     |   Expected
                 # ----------------------
                (100         ,        100), # Decimal
                ("42"        ,         42), # Decimal
            ]



        values += [
                 #        Octals
                 # ----------------------
                 # Input     |   Expected
                 # ----------------------
                (0o10        ,          8), # Octal
                ("0o20"      ,         16), # Octal
                ("020"       ,         16), # Octal
            ]


        values += [
                 #        Floats
                 # ----------------------
                 # Input     |   Expected
                 # ----------------------
                (3.14        ,       3.14), # Float
                ("2.72"      ,       2.72), # Float
                ("1e3"       ,       1000), # Float
                (1e-3        ,      0.001), # Float
            ]

        values += [
                 #        All ints
                 # ----------------------
                 # Input     |   Expected
                 # ----------------------
                ("0xA"       ,         10), 
                ("012"       ,         10), 
                ("0o12"      ,         10), 
                ("0b01010"   ,         10), 
                ("10"        ,         10), 
                ("10.0"      ,         10), 
                ("1e1"       ,         10), 
            ]

        for _input, expected in values:
            value = to_number(_input)

            if isinstance(_input, str):
                cmd = 'to_number("{}")'.format(_input)
            else:
                cmd = 'to_number({})'.format(_input)

            print("{:23} = {:10} == {:10}".format(cmd, value, expected))
            self.assertEqual(value, expected)

0

Posługiwać się:

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

0

Jest to funkcja, która konwertuje dowolny object(nie tylko str) na intlub float, w zależności od tego, czy podany ciąg znaków wygląda jak int lub float. Ponadto, jeśli jest to obiekt posiadający obie metody __floati __int__metody, domyślnie używa__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

-1

Za pomocą metod int i float możemy przekonwertować ciąg znaków na liczbę całkowitą i liczby zmiennoprzecinkowe.

s="45.8"
print(float(s))

y='67'
print(int(y))

Ta odpowiedź nie dodaje nic nowego. Zobacz na przykład tę odpowiedź, która zawiera te same informacje i więcej.
Georgy

-3

eval()jest bardzo dobrym rozwiązaniem tego pytania. Nie musi sprawdzać, czy liczba jest liczbą całkowitą czy zmienną, po prostu daje odpowiedni ekwiwalent. Jeśli wymagane są inne metody, spróbuj

if '.' in string:
    print(float(string))
else:
    print(int(string))

try-wyjątkiem może być również użyty jako alternatywa. Spróbuj przekonwertować ciąg znaków na int w bloku try. Jeśli ciąg będzie wartością zmiennoprzecinkową, wygeneruje błąd, który zostanie wyłapany w bloku wyjątkiem, tak jak to

try:
    print(int(string))
except:
    print(float(string))

-10

Oto kolejna interpretacja twojego pytania (wskazówka: jest niejasna). Możliwe, że szukasz czegoś takiego:

def parseIntOrFloat( aString ):
    return eval( aString )

Działa to tak ...

>>> parseIntOrFloat("545.2222")
545.22220000000004
>>> parseIntOrFloat("545")
545

Teoretycznie istnieje usterka polegająca na wstrzyknięciu. Łańcuch może na przykład być "import os; os.abort()". Jednak bez żadnego tła, skąd pochodzi ta struna, istnieje możliwość teoretycznych spekulacji. Ponieważ pytanie jest niejasne, wcale nie jest jasne, czy ta luka rzeczywiście istnieje, czy nie.


7
Nawet jeśli jego wkład jest w 100% bezpieczny, eval()jest ponad 3 razy wolniejszy niż try: int(s) except: float(s).
Cees Timmerman,

1
Cóż, evalto zła praktyka (musisz wiedzieć, ponieważ masz 310 tys. Reputacji)
U10-Forward
Korzystając z naszej strony potwierdzasz, że przeczytałeś(-aś) i rozumiesz nasze zasady używania plików cookie i zasady ochrony prywatności.
Licensed under cc by-sa 3.0 with attribution required.