Jaki jest najlepszy możliwy sposób sprawdzenia, czy ciąg może być reprezentowany jako liczba w Pythonie?
Obecnie posiadam funkcję:
def is_number(s):
try:
float(s)
return True
except ValueError:
return False
Co nie tylko jest brzydkie i powolne, wydaje się niezgrabne. Nie znalazłem jednak lepszej metody, ponieważ wywołanie float
funkcji głównej jest jeszcze gorsze.
python
casting
floating-point
type-conversion
Daniel Goldberg
źródło
źródło
x = float('0.00'); if x: use_float(x);
masz teraz błąd w kodzie. Prawdziwe wartości są powodem, dla którego funkcje te zgłaszają wyjątek, a nie zwracają goNone
w pierwszej kolejności. Lepszym rozwiązaniem jest po prostu uniknięcie funkcji narzędziowej i otoczenie połączenia, aby unosić się wtry catch
momencie, gdy chcesz go użyć.Odpowiedzi:
Spierałbym się o jedno i drugie.
Wyrażenie regularne lub inna metoda parsowania łańcuchów byłaby brzydsza i wolniejsza.
Nie jestem pewien, czy cokolwiek może być szybsze niż powyższe. Wywołuje funkcję i zwraca. Try / Catch nie wprowadza dużego obciążenia, ponieważ najczęstszy wyjątek jest wychwytywany bez obszernego wyszukiwania ramek stosu.
Problem polega na tym, że każda funkcja konwersji numerycznej ma dwa rodzaje wyników
C (na przykład) włamuje się do tego na wiele sposobów. Python określa to jasno i wyraźnie.
Myślę, że twój kod do tego jest idealny.
źródło
try
, więc umieszczam jąreturn True
welse
klauzulitry
. Jednym z powodów jest to, że z kodem w pytaniu, gdybym musiał go przejrzeć, musiałbym sprawdzić, czy drugie stwierdzenie wtry
klauzuli nie może wywołać błędu ValueError: oczywiście, nie wymaga to zbyt wiele czasu ani siły mózgu, ale po co używać, gdy nie jest potrzebny?IsNumeric()
albo kończę na try / catch lub innym zawijaniu try / catch. Ughif is_number(s): x = float(x) else: // fail
ma taką samą liczbę wierszy kodu jaktry: x = float(x) catch TypeError: # fail
. Ta funkcja użyteczności jest całkowicie niepotrzebną abstrakcją.Jeśli szukasz liczb całkowitych (dodatnich, niepodpisanych) zamiast liczb zmiennoprzecinkowych, możesz użyć
isdigit()
funkcji dla obiektów łańcuchowych.Metody łańcuchowe -
isdigit()
: Python2 , Python3Jest też coś w ciągach znaków Unicode, których nie znam zbytnio w Unicode - jest dziesiętny / dziesiętny
źródło
isdigit()
iint()
mają różne opinie na temat liczby całkowitej, np. Dla znaku Unicodeu'\u00b9'
:u'¹'.isdigit()
jest,True
aleint(u'¹')
podnosi ValueError.TL; DR Najlepszym rozwiązaniem jest
s.replace('.','',1).isdigit()
Zrobiłem kilka benchmarków porównując różne podejścia
Jeśli ciąg nie jest liczbą, blok wyjątków jest dość wolny. Ale co ważniejsze, metoda try-wyjątkiem jest jedynym podejściem, które poprawnie obsługuje notacje naukowe.
Notacja zmiennoprzecinkowa „.1234” nie jest obsługiwana przez:
- is_number_regex
Notacja naukowa „1.000000e + 50” nie jest obsługiwana przez:
- is_number_regex
- is_number_repl_isdigit
Notacja naukowa „1e50” nie jest obsługiwana przez:
- is_number_regex
- is_number_repl_isdigit
EDYCJA: Wyniki testu porównawczego
gdzie przetestowano następujące funkcje
źródło
s.replace('.','',1).isdigit()
) powinno pojawić się na początku tej odpowiedzi. W każdym razie powinna być zaakceptowana. Dzięki!'1.5e-9'
lub na negatywy.Jest jeden wyjątek, który możesz wziąć pod uwagę: ciąg „NaN”
Jeśli chcesz, aby is_number zwrócił FALSE dla „NaN”, ten kod nie będzie działał, ponieważ Python konwertuje go na reprezentację liczby, która nie jest liczbą (mów o problemach z tożsamością):
W przeciwnym razie powinienem naprawdę podziękować za fragment kodu, którego teraz intensywnie używam. :)
SOL.
źródło
NaN
może być dobrą wartością do zwrócenia (zamiastFalse
), jeśli przekazany tekst nie jest w rzeczywistości reprezentacją liczby. Sprawdzanie go jest rodzajem bólu (float
typ Pythona naprawdę potrzebuje do tego metody), ale można go używać w obliczeniach bez generowania błędu i wystarczy sprawdzić wynik.'inf'
. Alboinf
alboNaN
może być poprzedzony znakiem+
lub-
i nadal może być zaakceptowany.x-1 == x
jest prawdziwe dla dużych pływaków mniejszych niżinf
. W Pythonie 3.2 możesz używaćmath.isfinite
do testowania liczb, które nie są ani NaN, ani nieskończone, lub sprawdzać obamath.isnan
imath.isinf
przed tym.co powiesz na to:
która zwróci wartość prawdy tylko wtedy, gdy jest jedna lub nie ma jej. ” w ciągu cyfr.
zwróci fałsz
edycja: właśnie zobaczyłem kolejny komentarz ... można dodać
.replace(badstuff,'',maxnum_badstuff)
dla innych przypadków. jeśli podajesz sól, a nie arbitralne przyprawy (ref: xkcd # 974 ), to zrobi dobrze: Pźródło
1.234e56
(które mogą być również zapisane jako+1.234E+56
i kilka innych wariantów).re.match(r'^[+-]*(0[xbo])?[0-9A-Fa-f]*\.?[0-9A-Fa-f]*(E[+-]*[0-9A-Fa-f]+)$', 'str')
powinien lepiej wykonać ustalenie liczby (ale nie wszystkie, nie twierdzę, że). Nie polecam korzystania z tego, zdecydowanie lepiej jest użyć oryginalnego kodu Pytającego.Może to trochę przyzwyczaić się, ale jest to pythonowy sposób. Jak już wspomniano, alternatywy są gorsze. Ale jest jeszcze jedna zaleta robienia rzeczy w ten sposób: polimorfizm.
Główną ideą pisania kaczek jest to, że „jeśli chodzi i mówi jak kaczka, to jest to kaczka”. Co jeśli zdecydujesz, że musisz podklasować ciąg znaków, abyś mógł zmienić sposób określania, czy coś można przekształcić w liczbę zmiennoprzecinkową? A co, jeśli zdecydujesz się całkowicie przetestować jakiś inny obiekt? Możesz robić te rzeczy bez konieczności zmiany powyższego kodu.
Inne języki rozwiązują te problemy za pomocą interfejsów. Zapiszę analizę, które rozwiązanie jest lepsze dla innego wątku. Chodzi o to, że Python jest zdecydowanie po stronie pisania kaczki równania i prawdopodobnie będziesz musiał przyzwyczaić się do takiej składni, jeśli planujesz dużo programowania w Pythonie (ale to nie znaczy musisz to oczywiście polubić).
Jeszcze jedna rzecz, którą warto wziąć pod uwagę: Python jest dość szybki w rzucaniu i wychwytywaniu wyjątków w porównaniu do wielu innych języków (na przykład 30 razy szybszy niż .Net). Do licha, sam język generuje nawet wyjątki w komunikowaniu nietypowych, normalnych warunków programu (za każdym razem, gdy używasz pętli for). Dlatego nie martwiłbym się zbytnio aspektami wydajności tego kodu, dopóki nie zauważysz znaczącego problemu.
źródło
hasattr()
prostugetattr()
wywołanie zawarte wtry/except
. Mimo to obsługa wyjątków jest wolniejsza niż normalna kontrola przepływu, więc użycie jej do czegoś, co będzie prawdą przez większość czasu, może skutkować obniżeniem wydajności.Zaktualizowano po tym, jak Alfe wskazał, że nie trzeba sprawdzać pływaka osobno, ponieważ złożone obsługuje oba:
Wcześniej powiedziane: Czy w niektórych rzadkich przypadkach może być konieczne sprawdzenie liczb zespolonych (np. 1 + 2i), które nie mogą być reprezentowane przez liczbę zmiennoprzecinkową:
źródło
float()
całkowicie rozebrać materiał i po prostu sprawdzić, czycomplex()
połączenie zakończy się powodzeniem. Wszystko analizowane przezfloat()
może być analizowane przezcomplex()
.complex('(01989)')
wróci(1989+0j)
. Alefloat('(01989)')
zawiedzie. Myślę więc, że używaniecomplex
nie jest dobrym pomysłem.Aby
int
użyć tego:Ale
float
potrzebujemy kilku sztuczek ;-). Każda liczba zmiennoprzecinkowa ma jeden punkt ...Również dla liczb ujemnych po prostu dodaj
lstrip()
:A teraz mamy uniwersalny sposób:
źródło
1.234e56
i podobnych. Byłbym również zainteresowany tym, jak dowiesz się, że99999999999999999999e99999999999999999999
to nie jest liczba. Próbowanie parsowania szybko się sprawdza.Just Mimic C #
W języku C # istnieją dwie różne funkcje, które obsługują parsowanie wartości skalarnych:
float.parse ():
Uwaga: jeśli zastanawiasz się, dlaczego zmieniłem wyjątek na TypeError, oto dokumentacja .
float.try_parse ():
Uwaga: Nie chcesz zwracać wartości logicznej „False”, ponieważ nadal jest to typ wartości. Żadne nie jest lepsze, ponieważ wskazuje na niepowodzenie. Oczywiście, jeśli chcesz czegoś innego, możesz zmienić parametr fail na dowolny.
Aby rozszerzyć float o „parse ()” i „try_parse ()”, musisz dodać małpy do klasy „float”, aby dodać te metody.
Jeśli chcesz szanować istniejące wcześniej funkcje, kod powinien wyglądać następująco:
SideNote: Osobiście wolę nazywać to Monkey Punching, ponieważ wydaje mi się, że nadużywam języka, gdy to robię, ale YMMV.
Stosowanie:
A wielki Mędrzec Python powiedział do Stolicy Apostolskiej Sharpisus: „Wszystko, co możesz zrobić, mogę zrobić lepiej; Mogę zrobić wszystko lepiej niż ty”.
źródło
!
zamiastnot
może być drobnym błędem, ale zdecydowanie nie można przypisać atrybutów do wbudowanegofloat
w CPython.W przypadku ciągów nieliczbowych
try: except:
jest faktycznie wolniejszy niż wyrażenia regularne. W przypadku ciągów prawidłowych liczb wyrażenie regularne jest wolniejsze. Tak więc odpowiednia metoda zależy od danych wejściowych.Jeśli okaże się, że jesteś w powiązaniu z wydajnością, możesz użyć nowego modułu innej firmy o nazwie fastnumbers, który udostępnia funkcję o nazwie isfloat . Pełne ujawnienie, jestem autorem. Zawarłem jego wyniki w poniższych harmonogramach.
Jak widzisz
try: except:
był szybki dla wprowadzania numerycznego, ale bardzo wolny dla nieprawidłowego wprowadzaniafastnumbers
wygrywa w obu przypadkachźródło
prep_code_basis
iprep_code_re_method
zapobiegłoby mojej pomyłce.isfloat
funkcji?str(s).strip('-').replace('.','',1).isdigit()
jest około 10-krotnie wolniejsza!Wiem, że jest to szczególnie stare, ale dodam odpowiedź, która moim zdaniem obejmuje informacje brakujące w głosowaniu, które uzyskały najwyższą ocenę, które mogą być bardzo cenne dla każdego, kto to znajdzie:
Dla każdej z poniższych metod połącz je z liczbą, jeśli potrzebujesz jakichkolwiek danych wejściowych do zaakceptowania. (Zakładając, że używamy wokalnych definicji liczb całkowitych zamiast 0–255 itd.)
x.isdigit()
działa dobrze do sprawdzania, czy x jest liczbą całkowitą.x.replace('-','').isdigit()
działa dobrze do sprawdzania, czy x jest ujemne. (Sprawdź - w pierwszej pozycji)x.replace('.','').isdigit()
działa dobrze do sprawdzania, czy x jest liczbą dziesiętną.x.replace(':','').isdigit()
działa dobrze do sprawdzania, czy x jest stosunkiem.x.replace('/','',1).isdigit()
działa dobrze do sprawdzania, czy x jest ułamkiem.źródło
x.replace('/','',1).isdigit()
przeciwnym razie daty takie jak 07.04.2017 byłyby błędnie interpretowane jako liczby.Ta odpowiedź zawiera przewodnik krok po kroku mający funkcję z przykładami do znalezienia łańcucha:
Sprawdź, czy ciąg jest dodatnią liczbą całkowitą
Możesz użyć,
str.isdigit()
aby sprawdzić, czy podany ciąg jest dodatnią liczbą całkowitą.Przykładowe wyniki:
Sprawdź, czy ciąg jest dodatni / ujemny - liczba całkowita / liczba zmiennoprzecinkowa
str.isdigit()
zwraca,False
jeśli ciąg jest liczbą ujemną lub liczbą zmiennoprzecinkową. Na przykład:Jeśli chcesz również sprawdzić ujemne liczby całkowite
float
, a następnie możesz napisać niestandardową funkcję, aby to sprawdzić jako:Przykładowy przebieg:
Odrzuć ciągi „NaN” (nie liczbę) podczas sprawdzania liczby
Powyższe funkcje zwrócą
True
ciąg „NAN” (nie liczba), ponieważ dla Pythona jest to poprawna liczba zmiennoprzecinkowa, która nie jest liczbą. Na przykład:Aby sprawdzić, czy liczba to „NaN”, możesz użyć
math.isnan()
jako:Lub jeśli nie chcesz importować dodatkowej biblioteki, aby to sprawdzić, możesz po prostu to sprawdzić, porównując go z samym sobą
==
. Python zwraca,False
gdy liczbanan
zmiennoprzecinkowa jest porównywana z samym sobą. Na przykład:Stąd powyżej funkcja
is_number
może być aktualizowana, aby powrócićFalse
do"NaN"
jako:Przykładowy przebieg:
PS: Każda operacja dla każdej kontroli w zależności od rodzaju numeru wiąże się z dodatkowym kosztem. Wybierz wersję
is_number
funkcji, która odpowiada Twoim wymaganiom.źródło
Rzutowanie do float i przechwytywanie ValueError jest prawdopodobnie najszybszym sposobem, ponieważ float () jest specjalnie do tego przeznaczony. Wszystko inne, które wymaga analizowania ciągów (wyrażenia regularne itp.), Będzie prawdopodobnie wolniejsze, ponieważ nie jest dostrojone do tej operacji. Moje 0,02 $.
źródło
Możesz używać ciągów Unicode, mają metodę robienia tego, co chcesz:
Lub:
http://www.tutorialspoint.com/python/string_isnumeric.htm
http://docs.python.org/2/howto/unicode.html
źródło
s.isdecimal()
sprawdza, czys
łańcuch jest liczbą całkowitą nieujemną.s.isnumeric()
obejmuje postacie, któreint()
odrzucają.Chciałem zobaczyć, która metoda jest najszybsza. Ogólnie najlepsze i najbardziej spójne wyniki dała
check_replace
funkcja. Najszybsze wyniki dałacheck_exception
funkcja, ale tylko wtedy, gdy nie został zgłoszony żaden wyjątek - co oznacza, że jego kod jest najbardziej wydajny, ale narzut związany z rzuceniem wyjątku jest dość duży.Pamiętaj, że sprawdzanie poprawności rzutowania to jedyna metoda, która jest dokładna, na przykład działa to,
check_exception
ale pozostałe dwie funkcje testowe zwrócą wartość False dla prawidłowej liczby zmiennoprzecinkowej:Oto kod testu porównawczego:
Oto wyniki z Python 2.7.10 na MacBooku Pro 2017 2017:
Oto wyniki z Python 3.6.5 na MacBooku Pro 2017 2017:
Oto wyniki z PyPy 2.7.13 na MacBooku Pro 2017 2017:
źródło
Podsumowując, sprawdzając Nan, nieskończoność i liczby zespolone (wydaje się, że są one określone przez j, a nie i, tj. 1 + 2j), daje:
źródło
Dane wejściowe mogą być następujące:
a="50"
b=50
c=50.1
d="50.1"
1-Ogólne dane wejściowe:
Wejście tej funkcji może być wszystkim!
Sprawdza, czy podana zmienna jest liczbą. Ciągi liczbowe składają się z opcjonalnego znaku, dowolnej liczby cyfr, opcjonalnej części dziesiętnej i opcjonalnej części wykładniczej. Zatem + 0123.45e6 jest prawidłową wartością liczbową. Notacje szesnastkowe (np. 0xf4c3b00c) i binarne (np. 0b10100111001) są niedozwolone.
funkcja is_numeric
test:
is_floatfunkcja
Sprawdza, czy dana zmienna jest zmiennoprzecinkowa. ciągi pływające składają się z opcjonalnego znaku, dowolnej liczby cyfr, ...
test:
co jest ast ?
2- Jeśli masz pewność, że zmienna treść to String :
użyj metody str.isdigit ()
3-numeryczne wprowadzanie danych:
wykryj wartość int:
wykrywanie pływaka:
źródło
ast
”?Zrobiłem test prędkości. Powiedzmy, że jeśli łańcuch może być liczbą, strategia try / try jest najszybsza z możliwych. Jeśli łańcuch nie jest prawdopodobnie liczbą i jesteś zainteresowany sprawdzaniem liczb całkowitych , warto wykonać test (isdigit plus nagłówek „-”). Jeśli chcesz sprawdzić liczbę zmiennoprzecinkową, musisz użyć kodu try / oprócz bez znaku ucieczki.
źródło
Musiałem ustalić, czy ciąg rzutowany na podstawowe typy (float, int, str, bool). Po nie znalezieniu niczego w Internecie stworzyłem to:
Przykład
Możesz uchwycić typ i użyć go
źródło
RyanN sugeruje
Ale to nie do końca działa, ponieważ dla wystarczająco dużych pływaków
x-1 == x
zwraca true. Na przykład,2.0**54 - 1 == 2.0**54
źródło
Myślę, że twoje rozwiązanie jest w porządku, ale tak jest poprawna implementacja wyrażenia regularnego.
Wydaje się, że istnieje wiele nienawiści do wyrażeń regularnych wobec tych odpowiedzi, które moim zdaniem są nieuzasadnione, wyrażenia regularne mogą być dość czyste, poprawne i szybkie. To naprawdę zależy od tego, co próbujesz zrobić. Pierwotne pytanie brzmiało, jak „sprawdzić, czy ciąg może być reprezentowany przez liczbę (liczba zmiennoprzecinkowa)” (zgodnie z tytułem). Prawdopodobnie zechcesz użyć wartości liczbowej / zmiennoprzecinkowej po sprawdzeniu jej poprawności, w którym to przypadku próba / wyjątek ma sens. Ale jeśli z jakiegoś powodu chcesz po prostu sprawdzić, czy łańcuch jest liczbąto wyrażenie regularne również działa dobrze, ale trudno jest poprawić. Myślę, że większość dotychczasowych wyrażeń regularnych, na przykład, nie analizuje poprawnie ciągów znaków bez części całkowitej (takiej jak „.7”), która jest liczbą zmiennoprzecinkową, jeśli chodzi o python. Jest to nieco trudne do sprawdzenia w jednym wyrażeniu regularnym, w którym część ułamkowa nie jest wymagana. Dodałem dwa wyrażenia regularne, aby to pokazać.
Rodzi to interesujące pytanie, czym jest „liczba”. Czy dołączasz „inf”, który jest poprawny jako zmiennoprzecinkowy w Pythonie? Czy może zawierasz liczby, które są „liczbami”, ale może nie mogą być reprezentowane w pythonie (takie jak liczby większe niż liczba zmiennoprzecinkowa).
Istnieją również niejasności w sposobie przetwarzania liczb. Na przykład, co z „--20”? Czy to jest „liczba”? Czy to legalny sposób przedstawienia „20”? Python pozwoli ci zrobić „var = --20” i ustawić go na 20 (choć tak naprawdę dzieje się tak, ponieważ traktuje to jako wyrażenie), ale liczba zmiennoprzecinkowa („- 20”) nie działa.
W każdym razie, bez dodatkowych informacji, oto regex, który moim zdaniem obejmuje wszystkie inty i unosi się, gdy pyton je analizuje .
Niektóre przykładowe wartości testowe:
Uruchamianie benchmarkingu kod @ Ron-Reitera odpowiedziami pokazuje, że ten regex jest rzeczywiście szybciej niż normalny regex i jest znacznie szybciej na obsługę złych wartości niż wyjątkiem, co sprawia, że jakiś sens. Wyniki:
źródło
źródło
1e6
to liczba?Oto mój prosty sposób na zrobienie tego. Powiedzmy, że przeglądam niektóre ciągi i chcę je dodać do tablicy, jeśli okażą się liczbami.
Zamień plik myvar.apppend na dowolną operację, którą chcesz zrobić z łańcuchem, jeśli okaże się, że jest liczbą. Chodzi o to, aby spróbować użyć operacji float () i użyć zwróconego błędu, aby ustalić, czy łańcuch jest liczbą, czy nie.
źródło
Użyłem również funkcji, o której wspomniałeś, ale wkrótce zauważam, że ciągi znaków jako „Nan”, „Inf” i jej odmiany są uważane za liczbę. Proponuję więc ulepszoną wersję twojej funkcji, która zwróci false dla tego typu danych wejściowych i nie zawiedzie wariantów „1e3”:
źródło
Ten kod obsługuje wykładniki, liczby zmiennoprzecinkowe i liczby całkowite bez użycia wyrażenia regularnego.
źródło
Funkcja pomocnika użytkownika:
następnie
źródło
Możesz uogólnić technikę wyjątku w przydatny sposób, zwracając bardziej przydatne wartości niż Prawda i Fałsz. Na przykład ta funkcja umieszcza cudzysłowy w okrągłych ciągach, ale pozostawia liczby same. Właśnie tego potrzebowałem do szybkiego i brudnego filtra, aby stworzyć pewne zmienne definicje dla R.
źródło
Pracowałem nad problemem, który doprowadził mnie do tego wątku, a mianowicie jak przekonwertować zbiór danych na ciągi i liczby w najbardziej intuicyjny sposób. Po przeczytaniu oryginalnego kodu zrozumiałem, że to, czego potrzebowałem, było inne na dwa sposoby:
1 - Chciałem uzyskać wynik w postaci liczby całkowitej, jeśli ciąg reprezentował liczbę całkowitą
2 - Chciałem, aby wynik liczbowy lub ciągowy przylgnął do struktury danych
więc dostosowałem oryginalny kod, aby uzyskać tę pochodną:
źródło
Spróbuj tego.
źródło
is_number('10')
źródło