Bagaimana saya bisa memeriksa apakah string mewakili int, tanpa menggunakan coba / kecuali?
467
Apakah ada cara untuk mengetahui apakah string mewakili integer (misalnya '3',, '-17'tetapi tidak '3.14'atau 'asfasfas') Tanpa menggunakan mekanisme coba / kecuali?
Mengapa keduanya berusaha melakukan ini "dengan cara yang sulit?" Apa yang salah dengan coba / kecuali?
S.Lott
5
Ya, apa yang salah dengan coba / kecuali? Lebih baik meminta pengampunan daripada izin.
mk12
53
Saya akan bertanya mengapa hal sederhana ini perlu dicoba / kecuali? Sistem pengecualian adalah binatang yang kompleks, tetapi ini adalah masalah yang sederhana.
Aivar
13
@Aivar berhenti menyebarkan FUD. Satu percobaan / kecuali blok bahkan tidak mendekati "kompleks".
Triptych
47
Tapi itu tidak benar-benar FUD. Anda akan secara efektif menulis 4 baris kode, mengharapkan sesuatu meledak, menangkap pengecualian itu dan melakukan default Anda, daripada menggunakan satu liner.
andersonvom
Jawaban:
398
Jika Anda benar-benar kesal menggunakan try/excepts di semua tempat, harap tulis fungsi pembantu:
Jadi itu pythonic untuk memecahkan masalah sederhana dengan mekanisme yang kompleks? Ada algoritma untuk mendeteksi int yang ditulis di dalam fungsi "int" - Saya tidak melihat mengapa ini tidak diekspos sebagai fungsi boolean.
Aivar
79
@Aivar: Fungsi 5 baris ini bukan mekanisme yang kompleks.
Saya kira itu "pythonic" dalam arti bahwa jika Python berpikir string adalah int, begitu juga program Anda. Jika Python berubah, begitu juga program Anda, dan tanpa mengubah satu baris kode pun. Ada beberapa nilai dalam hal itu. Ini mungkin hal yang benar untuk dilakukan tergantung pada keadaan.
Shavais
57
Saya tidak tahu mengapa ini adalah jawaban yang diterima atau memiliki begitu banyak upvotes, karena ini persis kebalikan dari apa yang diminta OP.
FearlessFuture
757
dengan bilangan bulat positif yang dapat Anda gunakan .isdigit:
>>>'16'.isdigit()True
itu tidak bekerja dengan bilangan bulat negatif. misalkan Anda dapat mencoba yang berikut:
>>> s ='-17'>>> s.startswith('-')and s[1:].isdigit()True
itu tidak akan berfungsi dengan '16.0'format, yang mirip dengan intcasting dalam pengertian ini.
ini tidak menangani "+17" tanpa case khusus tambahan.
Bryan Oakley
1
Anda harus menguji untuk KEDUA kasus: lambda s: s.isdigit () atau (s.startswith ('-') dan s [1:]. Isdigit ())
rob
4
@Roberto: tentu saja Anda harus! dan saya yakin Anda mampu melakukannya!
SilentGhost
22
catatan: u'²'.isdigit()benar tetapi int(u'²')meningkatkan ValueError. Gunakan u.isdecimal()sebagai gantinya. str.isdigit()bergantung pada lokal pada Python 2.
Anda tahu, saya telah menemukan (dan saya telah menguji ini berulang-ulang) yang mencoba / kecuali tidak melakukan semua itu dengan baik, untuk alasan apa pun. Saya sering mencoba beberapa cara melakukan hal-hal, dan saya tidak berpikir saya pernah menemukan metode yang menggunakan try / kecuali untuk melakukan yang terbaik dari yang diuji, pada kenyataannya tampaknya bagi saya metode-metode itu biasanya keluar dekat dengan terburuk, kalau bukan yang terburuk. Tidak dalam setiap kasus, tetapi dalam banyak kasus. Saya tahu banyak orang mengatakan itu adalah cara "Pythonic", tapi itu satu area di mana saya berpisah dengan mereka. Bagi saya, itu tidak terlalu berkinerja atau sangat elegan, jadi, saya cenderung hanya menggunakannya untuk menjebak dan melaporkan kesalahan.
Saya akan mengeluh bahwa PHP, perl, ruby, C, dan bahkan shell freaking memiliki fungsi sederhana untuk menguji string untuk integer-hood, tetapi karena ketekunan dalam memverifikasi asumsi-asumsi itu membuat saya tersandung! Rupanya kekurangan ini adalah penyakit yang umum.
Berikut ini edit tulisan Bruno yang cepat dan kotor:
import sys, time, re
g_intRegex = re.compile(r"^([+-]?[1-9]\d*|0)$")
testvals =[# integers0,1,-1,1.0,-1.0,'0','0.','0.0','1','-1','+1','1.0','-1.0','+1.0','06',# non-integers'abc 123',1.1,-1.1,'1.1','-1.1','+1.1','1.1.1','1.1.0','1.0.1','1.0.0','1.0.','1..0','1..','0.0.','0..0','0..','one', object(),(1,2,3),[1,2,3],{'one':'two'},# with spaces' 0 ',' 0.',' .0','.01 ']def isInt_try(v):try: i = int(v)except:returnFalsereturnTruedef isInt_str(v):
v = str(v).strip()return v=='0'or(v if v.find('..')>-1else v.lstrip('-+').rstrip('0').rstrip('.')).isdigit()def isInt_re(v):import re
ifnot hasattr(isInt_re,'intRegex'):
isInt_re.intRegex = re.compile(r"^([+-]?[1-9]\d*|0)$")return isInt_re.intRegex.match(str(v).strip())isnotNonedef isInt_re2(v):return g_intRegex.match(str(v).strip())isnotNonedef check_int(s):
s = str(s)if s[0]in('-','+'):return s[1:].isdigit()return s.isdigit()def timeFunc(func, times):
t1 = time.time()for n in range(times):for v in testvals:
r = func(v)
t2 = time.time()return t2 - t1
def testFuncs(funcs):for func in funcs:
sys.stdout.write("\t%s\t|"% func.__name__)print()for v in testvals:if type(v)== type(''):
sys.stdout.write("'%s'"% v)else:
sys.stdout.write("%s"% str(v))for func in funcs:
sys.stdout.write("\t\t%s\t|"% func(v))
sys.stdout.write("\r\n")if __name__ =='__main__':print()print("tests..")
testFuncs((isInt_try, isInt_str, isInt_re, isInt_re2, check_int))print()print("timings..")print("isInt_try: %6.4f"% timeFunc(isInt_try,10000))print("isInt_str: %6.4f"% timeFunc(isInt_str,10000))print("isInt_re: %6.4f"% timeFunc(isInt_re,10000))print("isInt_re2: %6.4f"% timeFunc(isInt_re2,10000))print("check_int: %6.4f"% timeFunc(check_int,10000))
Metode AC dapat memindai Sekali Melalui, dan dilakukan. Metode AC yang memindai string sekali melalui akan menjadi Hal yang Benar untuk dilakukan, saya pikir.
EDIT:
Saya telah memperbarui kode di atas untuk bekerja di Python 3.5, dan untuk memasukkan fungsi check_int dari jawaban yang paling banyak dipilih saat ini, dan untuk menggunakan regex paling populer saat ini yang dapat saya temukan untuk pengujian integer-hood. Regex ini menolak string seperti 'abc 123'. Saya telah menambahkan 'abc 123' sebagai nilai tes.
Sangat menarik bagi saya untuk mencatat, pada titik ini, bahwa TIDAK ada fungsi yang diuji, termasuk metode coba, fungsi check_int yang populer, dan regex paling populer untuk pengujian integer-hood, mengembalikan jawaban yang benar untuk semua nilai tes (baik, tergantung pada apa yang Anda pikirkan jawaban yang benar; lihat hasil tes di bawah).
Fungsi built-in int () secara diam-diam memotong bagian fraksional dari angka titik mengambang dan mengembalikan bagian bilangan bulat sebelum desimal, kecuali jika angka titik mengambang pertama kali dikonversi ke string.
Fungsi check_int () mengembalikan false untuk nilai-nilai seperti 0,0 dan 1.0 (yang secara teknis bilangan bulat) dan mengembalikan true untuk nilai-nilai seperti '06'.
Berkinerja hampir sama baiknya dengan check_int (0.3486) dan mengembalikan nilai true seperti 1.0 dan 0.0 dan +1.0 dan 0. dan .0 dan seterusnya. Tetapi juga mengembalikan true untuk '06', jadi. Pilih racunmu, kurasa.
Mungkin sebagian darinya berasal dari fakta bahwa bilangan bulat sedikit berubah-ubah sendiri. Sebuah sistem pemrograman tidak dapat mengambil asumsi mewah bahwa itu akan selalu menjadi representasi desimal. 0x4df, bilangan bulat yang valid di beberapa tempat, dan 0891 tidak di tempat lain. Saya takut memikirkan apa yang mungkin timbul karena adanya unicode dalam jenis cek ini.
PlexQ
3
+1 untuk waktu. Saya setuju bahwa seluruh bisnis pengecualian ini tidak benar-benar elegan untuk pertanyaan sederhana seperti itu. Anda akan mengharapkan metode build in helper untuk masalah umum seperti itu ...
RickyA
9
Saya tahu utas ini pada dasarnya tidak aktif, tetapi +1 untuk mempertimbangkan run-time. Panjang garis tidak selalu menunjukkan kompleksitas yang mendasarinya; dan tentu saja, coba / kecuali mungkin terlihat sederhana (dan mudah dibaca, yang juga penting), tetapi ini adalah operasi yang mahal. Saya berpendapat hierarki preferensi harus selalu terlihat seperti berikut: 1. Solusi eksplisit yang mudah dibaca (milik SilentGhost). 2. Solusi implisit yang mudah dibaca (Triptych's). 3. Tidak ada tiga.
Eric Humphrey
1
Terima kasih atas investigasi tourough Anda mengenai topik yang tampaknya tidak penting ini. Saya akan menggunakan isInt_str (), pythonic atau tidak. Yang mengganggu saya adalah bahwa saya belum menemukan apa pun tentang arti v.find ('..'). Apakah itu semacam sintaks find khusus atau case-edge dari numeric-string?
JackLeEmmerdeur
3
Ya, agak ketinggalan jaman tapi analisisnya masih sangat bagus dan relevan. Dalam Python 3.5 trylebih efisien: isInt_try: 0.6552 / isInt_str: 0.6396 / isInt_re: 1.0296 / isInt_re2: 0.5168.
EDIT : Seperti yang ditunjukkan @BuzzMoschetti, cara ini akan gagal untuk angka minus (mis., "-23" ). Jika input_num Anda kurang dari 0, gunakan re.sub (regex_search, regex_replace, content) sebelum menerapkan str.isdigit () . Sebagai contoh:
import re
input_num ="-23"
input_num = re.sub("^-","", input_num)## "^" indicates to remove the first "-" only
str.isdigit(input_num)## True
@BuzzMoschetti Anda benar. Cara cepat untuk memperbaikinya adalah menghapus tanda minus dengan re.replace (regex_search, regex_replace, content) sebelum menerapkan str.isdigit ()
Catbuilts
27
Gunakan ekspresi reguler:
import re
defRepresentsInt(s):return re.match(r"[-+]?\d+$", s)isnotNone
+1: mengungkapkan bahwa ini sangat rumit dan mahal jika dibandingkan dengan coba / kecuali.
S.Lott
2
Saya merasa ini pada dasarnya lebih lambat, versi kustom dari solusi 'isnumerik' yang ditawarkan oleh @SilentGhost.
Greg
@Greg: Karena @SilentGhost tidak menutupi tanda-tanda dengan benar, versi ini benar-benar berfungsi.
S.Lott
1
@ S.Lott: tentu saja, siapa pun yang dapat memposting di SO, akan dapat memperluas contoh saya untuk menutupi tanda-tanda.
SilentGhost
2
ekspresi reguler adalah tentang hal yang paling kompleks dan tidak jelas yang ada, saya menemukan bahwa pemeriksaan sederhana di atas secara substansial lebih jelas, bahkan jika saya pikir itu masih jelek, ini lebih buruk.
PlexQ
18
Solusi RegEx yang tepat akan menggabungkan ide-ide Greg Hewgill dan Nowell, tetapi tidak menggunakan variabel global. Anda dapat melakukannya dengan melampirkan atribut ke metode ini. Juga, saya tahu bahwa itu tidak disukai untuk memasukkan impor dalam suatu metode, tetapi yang saya maksudkan adalah efek "modul malas" seperti http://peak.telecommunity.com/DevCenter/Importing#lazy-imports
sunting: Teknik favorit saya sejauh ini adalah menggunakan metode eksklusif objek String.
#!/usr/bin/env python# Uses exclusively methods of the String objectdef isInteger(i):
i = str(i)return i=='0'or(i if i.find('..')>-1else i.lstrip('-+').rstrip('0').rstrip('.')).isdigit()# Uses re module for regexdef isIntegre(i):import re
ifnot hasattr(isIntegre,'_re'):print("I compile only once. Remove this line when you are confident in that.")
isIntegre._re = re.compile(r"[-+]?\d+(\.0*)?$")return isIntegre._re.match(str(i))isnotNone# When executed directly run Unit Testsif __name__ =='__main__':for obj in[# integers0,1,-1,1.0,-1.0,'0','0.','0.0','1','-1','+1','1.0','-1.0','+1.0',# non-integers1.1,-1.1,'1.1','-1.1','+1.1','1.1.1','1.1.0','1.0.1','1.0.0','1.0.','1..0','1..','0.0.','0..0','0..','one', object(),(1,2,3),[1,2,3],{'one':'two'}]:# Notice the integre uses 're' (intended to be humorous)
integer =('an integer'if isInteger(obj)else'NOT an integer')
integre =('an integre'if isIntegre(obj)else'NOT an integre')# Make strings look like strings in the outputif isinstance(obj, str):
obj =("'%s'"%(obj,))print("%30s is %14s is %14s"%(obj, integer, integre))
Dan untuk anggota kelas yang kurang berani, inilah hasilnya:
I compile only once.Remove this line when you are confident in that.0is an integer is an integre
1is an integer is an integre
-1is an integer is an integre
1.0is an integer is an integre
-1.0is an integer is an integre
'0'is an integer is an integre
'0.'is an integer is an integre
'0.0'is an integer is an integre
'1'is an integer is an integre
'-1'is an integer is an integre
'+1'is an integer is an integre
'1.0'is an integer is an integre
'-1.0'is an integer is an integre
'+1.0'is an integer is an integre
1.1is NOT an integer is NOT an integre
-1.1is NOT an integer is NOT an integre
'1.1'is NOT an integer is NOT an integre
'-1.1'is NOT an integer is NOT an integre
'+1.1'is NOT an integer is NOT an integre
'1.1.1'is NOT an integer is NOT an integre
'1.1.0'is NOT an integer is NOT an integre
'1.0.1'is NOT an integer is NOT an integre
'1.0.0'is NOT an integer is NOT an integre
'1.0.'is NOT an integer is NOT an integre
'1..0'is NOT an integer is NOT an integre
'1..'is NOT an integer is NOT an integre
'0.0.'is NOT an integer is NOT an integre
'0..0'is NOT an integer is NOT an integre
'0..'is NOT an integer is NOT an integre
'one'is NOT an integer is NOT an integre
<object object at 0x103b7d0a0>is NOT an integer is NOT an integre
(1,2,3)is NOT an integer is NOT an integre
[1,2,3]is NOT an integer is NOT an integre
{'one':'two'}is NOT an integer is NOT an integre
Saya akan setuju bahwa suite pengujian saya berlebihan. Saya suka membuktikan bahwa kode saya berfungsi saat saya menulisnya. Tapi apakah Anda pikir fungsi isInteger saya berlebihan? Tentunya tidak.
Bruno Bronosky
1
Saya baru saja mendapatkan suara tanpa komentar. Ada apa dengan orang? Saya mengerti bahwa milenium sekarang menggunakan "Suka" sebagai "baca tanda terima". Tetapi apakah mereka sekarang menggunakan down vote sebagai penanda "bukan metode yang saya pilih"? Mungkin mereka tidak menyadari itu mengurangi 2 poin dari reputasi ANDA SENDIRI untuk memilih suara. SO / SE melakukan itu untuk mendorong turunnya pemungutan suara hanya karena informasi yang salah, dalam hal ini saya harap Anda akan meninggalkan komentar .
Pendekatan Greg Hewgill kehilangan beberapa komponen: "^" yang memimpin hanya cocok dengan awal string, dan menyusun ulang sebelumnya. Tetapi pendekatan ini akan memungkinkan Anda untuk menghindari mencoba: kecuali:
import re
INT_RE = re.compile(r"^[-]?\d+$")defRepresentsInt(s):return INT_RE.match(str(s))isnotNone
Saya akan tertarik mengapa Anda mencoba untuk menghindari mencoba: kecuali?
Soal gaya. Saya pikir "coba / kecuali" harus digunakan hanya dengan kesalahan aktual, bukan dengan aliran program normal.
Adam Matan
2
@Udi Pasmon: Python menggunakan cukup banyak coba / kecuali untuk aliran program "normal". Misalnya, setiap iterator berhenti dengan pengecualian yang dimunculkan.
S.Lott
3
-1: Meskipun petunjuk Anda untuk menyusun regex benar, Anda salah dalam mengkritik Greg dalam hal lain: re.match cocok dengan permulaan string, sehingga ^ dalam pola sebenarnya berlebihan. (Ini berbeda ketika Anda menggunakan penelitian ulang).
ThomasH
S.Lott - Apakah aliran ini dianggap masuk akal dalam python? Apa bedanya dengan bahasa lain? Mungkin itu layak untuk pertanyaan terpisah.
Adam Matan
1
Penggunaan / kecuali Python yang berat telah dibahas di sini pada SO. Coba cari '[python] kecuali'
S.Lott
4
Saya harus melakukan ini sepanjang waktu, dan saya memiliki keengganan yang ringan tetapi diakui tidak rasional untuk menggunakan pola coba / kecuali. Saya menggunakan ini:
all([xi in'1234567890'for xi in x])
Itu tidak mengakomodasi angka negatif, jadi Anda bisa menghilangkan satu tanda minus (jika ada), dan kemudian memeriksa apakah hasilnya terdiri dari angka 0-9:
all([xi in'1234567890'for xi in x.replace('-','',1)])
Anda juga bisa meneruskan x ke str () jika Anda tidak yakin inputnya berupa string:
all([xi in'1234567890'for xi in str(x).replace('-','',1)])
Setidaknya ada dua (tepi?) Kasus di mana ini berantakan:
Ini tidak berfungsi untuk berbagai notasi ilmiah dan / atau eksponensial (mis. 1.2E3, 10 ^ 3, dll.) - keduanya akan menghasilkan False. Saya tidak berpikir jawaban lain mengakomodasi ini baik, dan bahkan Python 3.8 memiliki pendapat yang tidak konsisten, karena type(1E2)memberi <class 'float'>sedangkan type(10^2)memberi<class 'int'> .
Input string kosong memberi True.
Jadi itu tidak akan berfungsi untuk setiap input yang mungkin, tetapi jika Anda dapat mengecualikan notasi ilmiah, notasi eksponensial, dan string kosong, ini merupakan pemeriksaan satu-baris OK yang mengembalikan Falsejika x bukan bilangan bulat danTrue jika x adalah bilangan bulat.
Saya tidak tahu apakah ini pythonic, tetapi hanya satu baris, dan relatif jelas apa yang dilakukan oleh kode tersebut.
Coba / kecuali sepertinya berjalan di atas rumput seseorang (coba) dan kemudian jika / ketika mereka melihat dan menjadi marah (pengecualian) Anda meminta maaf (menangani pengecualian), sedangkan all(xi in '1234567890' for xi in x])pola saya sepertinya lebih seperti meminta izin untuk berjalan melintasi halaman. Saya tidak senang menjadi penanya izin, tapi di sini kita.
Coba tebak apa yang replaceterjadi? Juga, ini akan salah menerima 5-2, misalnya.
Ry-
Akan melempar IndexError jikas='-'
Anti Earth
s = '-'; s.replace ('-', '') .isdigit () -> False
Vladyslav Savchenko
2
Saya sangat menyukai pos Shavais, tetapi saya menambahkan satu lagi test case (& fungsi isdigit () bawaan):
def isInt_loop(v):
v = str(v).strip()# swapping '0123456789' for '9876543210' makes nominal difference (might have because '1' is toward the beginning of the string)
numbers ='0123456789'for i in v:if i notin numbers:returnFalsereturnTruedef isInt_Digit(v):
v = str(v).strip()return v.isdigit()
Kedua dua test case yang saya tambahkan (isInt_loop dan isInt_digit) lulus test case yang sama persis (mereka berdua hanya menerima bilangan bulat yang tidak ditandatangani), tetapi saya pikir orang bisa lebih pandai dengan memodifikasi implementasi string (isInt_loop) yang bertentangan dengan isdigit built in () berfungsi, jadi saya memasukkannya, meskipun ada sedikit perbedaan dalam waktu eksekusi. (dan kedua metode ini mengalahkan semuanya, tetapi jangan menangani hal-hal tambahan: "./+/-")
Juga, saya menemukan itu menarik untuk dicatat bahwa regex (metode isInt_re2) mengalahkan perbandingan string dalam tes yang sama yang dilakukan oleh Shavais pada 2012 (saat ini 2018). Mungkin perpustakaan regex telah diperbaiki?
Ini mungkin cara yang paling mudah dan pythonic untuk mendekatinya menurut saya. Saya tidak melihat solusi ini dan pada dasarnya sama dengan regex, tetapi tanpa regex.
set(input_string) == set(string.digits)jika kita lewati '-+ 'di awal dan .0, E-1di akhir.
jfs
1
Berikut adalah fungsi yang mem-parsing tanpa memunculkan kesalahan. Ini menangani kasus yang jelas pengembalian Nonekegagalan (menangani tanda-tanda 2000 '- / +' secara default di CPython!):
#!/usr/bin/env pythondef get_int(number):
splits = number.split('.')if len(splits)>2:# too many splitsreturnNoneif len(splits)==2and splits[1]:# handle decimal part recursively :-)if get_int(splits[1])!=0:returnNone
int_part = splits[0].lstrip("+")if int_part.startswith('-'):# handle minus sign recursively :-)return get_int(int_part[1:])*-1# successful 'and' returns last truth-y value (cast is always valid)return int_part.isdigit()and int(int_part)
Beberapa tes:
tests =["0","0.0","0.1","1","1.1","1.0","-1","-1.1","-1.0","-0","--0","---3",'.3','--3.',"+13","+-1.00","--+123","-0.000"]for t in tests:print"get_int(%s) = %s"%(t, get_int(str(t)))
Mengevaluasi simpul ekspresi atau string yang berisi tampilan Python literal atau wadah dengan aman. String atau simpul yang disediakan hanya dapat terdiri dari struktur literal Python berikut: string, byte, angka, tupel, daftar, dikte, set, boolean, dan Tidak ada.
Saya harus mencatat bahwa ini akan menimbulkan ValueErrorpengecualian ketika dipanggil terhadap apa pun yang bukan merupakan Python literal. Karena pertanyaannya meminta solusi tanpa mencoba / kecuali, saya punya solusi tipe Kobayashi-Maru untuk itu:
from ast import literal_eval
from contextlib import suppress
def is_int(s):with suppress(ValueError):return isinstance(literal_eval(s), int)returnFalse
Saya kira pertanyaannya terkait dengan kecepatan karena percobaan / kecuali memiliki penalti waktu:
data uji
Pertama, saya membuat daftar 200 string, 100 string gagal dan 100 string numerik.
from random import shuffle
numbers =[u'+1']*100
nonumbers =[u'1abc']*100
testlist = numbers + nonumbers
shuffle(testlist)
testlist = np.array(testlist)
solusi numpy (hanya bekerja dengan array dan unicode)
np.core.defchararray.isnumeric juga dapat bekerja dengan string unicode np.core.defchararray.isnumeric(u'+12')tetapi ia kembali dan array. Jadi, ini solusi yang bagus jika Anda harus melakukan ribuan konversi dan kehilangan data atau data non numerik.
import numpy as np
%timeit np.core.defchararray.isnumeric(testlist)10000 loops, best of 3:27.9µs per loop # 200 numbers per loop
coba / kecuali
def check_num(s):try:
int(s)returnTrueexcept:returnFalsedef check_list(l):return[check_num(e)for e in l]%timeit check_list(testlist)1000 loops, best of 3:217µs per loop # 200 numbers per loop
Jawaban:
Jika Anda benar-benar kesal menggunakan
try/except
s di semua tempat, harap tulis fungsi pembantu:Ini akan menjadi kode WAY lebih banyak untuk menutupi semua string yang oleh Python dianggap integer. Saya katakan hanya pythonic yang satu ini.
sumber
>>> print RepresentsInt(10.0)
True
>>> print RepresentsInt(10.06)
True
dengan bilangan bulat positif yang dapat Anda gunakan
.isdigit
:itu tidak bekerja dengan bilangan bulat negatif. misalkan Anda dapat mencoba yang berikut:
itu tidak akan berfungsi dengan
'16.0'
format, yang mirip denganint
casting dalam pengertian ini.edit :
sumber
u'²'.isdigit()
benar tetapiint(u'²')
meningkatkan ValueError. Gunakanu.isdecimal()
sebagai gantinya.str.isdigit()
bergantung pada lokal pada Python 2.check_int('')
akan menaikkan pengecualian alih-alih kembaliFalse
Anda tahu, saya telah menemukan (dan saya telah menguji ini berulang-ulang) yang mencoba / kecuali tidak melakukan semua itu dengan baik, untuk alasan apa pun. Saya sering mencoba beberapa cara melakukan hal-hal, dan saya tidak berpikir saya pernah menemukan metode yang menggunakan try / kecuali untuk melakukan yang terbaik dari yang diuji, pada kenyataannya tampaknya bagi saya metode-metode itu biasanya keluar dekat dengan terburuk, kalau bukan yang terburuk. Tidak dalam setiap kasus, tetapi dalam banyak kasus. Saya tahu banyak orang mengatakan itu adalah cara "Pythonic", tapi itu satu area di mana saya berpisah dengan mereka. Bagi saya, itu tidak terlalu berkinerja atau sangat elegan, jadi, saya cenderung hanya menggunakannya untuk menjebak dan melaporkan kesalahan.
Saya akan mengeluh bahwa PHP, perl, ruby, C, dan bahkan shell freaking memiliki fungsi sederhana untuk menguji string untuk integer-hood, tetapi karena ketekunan dalam memverifikasi asumsi-asumsi itu membuat saya tersandung! Rupanya kekurangan ini adalah penyakit yang umum.
Berikut ini edit tulisan Bruno yang cepat dan kotor:
Berikut adalah hasil perbandingan kinerja:
Metode AC dapat memindai Sekali Melalui, dan dilakukan. Metode AC yang memindai string sekali melalui akan menjadi Hal yang Benar untuk dilakukan, saya pikir.
EDIT:
Saya telah memperbarui kode di atas untuk bekerja di Python 3.5, dan untuk memasukkan fungsi check_int dari jawaban yang paling banyak dipilih saat ini, dan untuk menggunakan regex paling populer saat ini yang dapat saya temukan untuk pengujian integer-hood. Regex ini menolak string seperti 'abc 123'. Saya telah menambahkan 'abc 123' sebagai nilai tes.
Sangat menarik bagi saya untuk mencatat, pada titik ini, bahwa TIDAK ada fungsi yang diuji, termasuk metode coba, fungsi check_int yang populer, dan regex paling populer untuk pengujian integer-hood, mengembalikan jawaban yang benar untuk semua nilai tes (baik, tergantung pada apa yang Anda pikirkan jawaban yang benar; lihat hasil tes di bawah).
Fungsi built-in int () secara diam-diam memotong bagian fraksional dari angka titik mengambang dan mengembalikan bagian bilangan bulat sebelum desimal, kecuali jika angka titik mengambang pertama kali dikonversi ke string.
Fungsi check_int () mengembalikan false untuk nilai-nilai seperti 0,0 dan 1.0 (yang secara teknis bilangan bulat) dan mengembalikan true untuk nilai-nilai seperti '06'.
Berikut adalah hasil tes (Python 3.5) saat ini:
Baru saja saya mencoba menambahkan fungsi ini:
Berkinerja hampir sama baiknya dengan check_int (0.3486) dan mengembalikan nilai true seperti 1.0 dan 0.0 dan +1.0 dan 0. dan .0 dan seterusnya. Tetapi juga mengembalikan true untuk '06', jadi. Pilih racunmu, kurasa.
sumber
try
lebih efisien: isInt_try: 0.6552 / isInt_str: 0.6396 / isInt_re: 1.0296 / isInt_re2: 0.5168.str.isdigit()
harus melakukan trik.Contoh:
EDIT : Seperti yang ditunjukkan @BuzzMoschetti, cara ini akan gagal untuk angka minus (mis., "-23" ). Jika input_num Anda kurang dari 0, gunakan re.sub (regex_search, regex_replace, content) sebelum menerapkan str.isdigit () . Sebagai contoh:
sumber
Gunakan ekspresi reguler:
Jika Anda harus menerima pecahan desimal juga:
Untuk peningkatan kinerja jika Anda sering melakukan ini, kompilasi ekspresi reguler hanya sekali menggunakan
re.compile()
.sumber
Solusi RegEx yang tepat akan menggabungkan ide-ide Greg Hewgill dan Nowell, tetapi tidak menggunakan variabel global. Anda dapat melakukannya dengan melampirkan atribut ke metode ini. Juga, saya tahu bahwa itu tidak disukai untuk memasukkan impor dalam suatu metode, tetapi yang saya maksudkan adalah efek "modul malas" seperti http://peak.telecommunity.com/DevCenter/Importing#lazy-imports
sunting: Teknik favorit saya sejauh ini adalah menggunakan metode eksklusif objek String.
Dan untuk anggota kelas yang kurang berani, inilah hasilnya:
sumber
Jadi fungsi Anda adalah:
sumber
Pendekatan Greg Hewgill kehilangan beberapa komponen: "^" yang memimpin hanya cocok dengan awal string, dan menyusun ulang sebelumnya. Tetapi pendekatan ini akan memungkinkan Anda untuk menghindari mencoba: kecuali:
Saya akan tertarik mengapa Anda mencoba untuk menghindari mencoba: kecuali?
sumber
Saya harus melakukan ini sepanjang waktu, dan saya memiliki keengganan yang ringan tetapi diakui tidak rasional untuk menggunakan pola coba / kecuali. Saya menggunakan ini:
Itu tidak mengakomodasi angka negatif, jadi Anda bisa menghilangkan satu tanda minus (jika ada), dan kemudian memeriksa apakah hasilnya terdiri dari angka 0-9:
Anda juga bisa meneruskan x ke str () jika Anda tidak yakin inputnya berupa string:
Setidaknya ada dua (tepi?) Kasus di mana ini berantakan:
type(1E2)
memberi<class 'float'>
sedangkantype(10^2)
memberi<class 'int'>
.Jadi itu tidak akan berfungsi untuk setiap input yang mungkin, tetapi jika Anda dapat mengecualikan notasi ilmiah, notasi eksponensial, dan string kosong, ini merupakan pemeriksaan satu-baris OK yang mengembalikan
False
jika x bukan bilangan bulat danTrue
jika x adalah bilangan bulat.Saya tidak tahu apakah ini pythonic, tetapi hanya satu baris, dan relatif jelas apa yang dilakukan oleh kode tersebut.
sumber
all(xi in '1234567890' for xi in x])
pola saya sepertinya lebih seperti meminta izin untuk berjalan melintasi halaman. Saya tidak senang menjadi penanya izin, tapi di sini kita.kupikir
akan lebih baik untuk menulis ulang ke:
karena s [1:] juga membuat string baru
Tetapi solusi yang jauh lebih baik adalah
sumber
replace
terjadi? Juga, ini akan salah menerima5-2
, misalnya.s='-'
Saya sangat menyukai pos Shavais, tetapi saya menambahkan satu lagi test case (& fungsi isdigit () bawaan):
dan secara signifikan mengalahkan waktu sisanya:
menggunakan normal 2,7 python:
Kedua dua test case yang saya tambahkan (isInt_loop dan isInt_digit) lulus test case yang sama persis (mereka berdua hanya menerima bilangan bulat yang tidak ditandatangani), tetapi saya pikir orang bisa lebih pandai dengan memodifikasi implementasi string (isInt_loop) yang bertentangan dengan isdigit built in () berfungsi, jadi saya memasukkannya, meskipun ada sedikit perbedaan dalam waktu eksekusi. (dan kedua metode ini mengalahkan semuanya, tetapi jangan menangani hal-hal tambahan: "./+/-")
Juga, saya menemukan itu menarik untuk dicatat bahwa regex (metode isInt_re2) mengalahkan perbandingan string dalam tes yang sama yang dilakukan oleh Shavais pada 2012 (saat ini 2018). Mungkin perpustakaan regex telah diperbaiki?
sumber
Ini mungkin cara yang paling mudah dan pythonic untuk mendekatinya menurut saya. Saya tidak melihat solusi ini dan pada dasarnya sama dengan regex, tetapi tanpa regex.
sumber
set(input_string) == set(string.digits)
jika kita lewati'-+ '
di awal dan.0
,E-1
di akhir.Berikut adalah fungsi yang mem-parsing tanpa memunculkan kesalahan. Ini menangani kasus yang jelas pengembalian
None
kegagalan (menangani tanda-tanda 2000 '- / +' secara default di CPython!):Beberapa tes:
Hasil:
Untuk kebutuhan Anda, Anda dapat menggunakan:
sumber
Saya menyarankan yang berikut ini:
Dari dokumen :
Saya harus mencatat bahwa ini akan menimbulkan
ValueError
pengecualian ketika dipanggil terhadap apa pun yang bukan merupakan Python literal. Karena pertanyaannya meminta solusi tanpa mencoba / kecuali, saya punya solusi tipe Kobayashi-Maru untuk itu:¯ \ _ (ツ) _ / ¯
sumber
Saya punya satu kemungkinan yang tidak menggunakan int sama sekali, dan tidak boleh menimbulkan pengecualian kecuali string tidak mewakili angka
Ini harus bekerja untuk semua jenis string yang mengapung menerima, positif, negatif, notasi teknik ...
sumber
Saya kira pertanyaannya terkait dengan kecepatan karena percobaan / kecuali memiliki penalti waktu:
data uji
Pertama, saya membuat daftar 200 string, 100 string gagal dan 100 string numerik.
solusi numpy (hanya bekerja dengan array dan unicode)
np.core.defchararray.isnumeric juga dapat bekerja dengan string unicode
np.core.defchararray.isnumeric(u'+12')
tetapi ia kembali dan array. Jadi, ini solusi yang bagus jika Anda harus melakukan ribuan konversi dan kehilangan data atau data non numerik.coba / kecuali
Tampaknya solusi numpy jauh lebih cepat.
sumber
Jika Anda hanya ingin menerima digit ascii rendah, berikut ini beberapa tes untuk melakukannya:
Python 3.7+:
(u.isdecimal() and u.isascii())
Python <= 3.6:
(u.isdecimal() and u == str(int(u)))
Jawaban lain menyarankan menggunakan
.isdigit()
atau.isdecimal()
tetapi keduanya termasuk beberapa karakter kode-atas seperti'٢'
(u'\u0662'
):sumber
int()
.Uh .. Coba ini:
Ini berfungsi jika Anda tidak meletakkan string yang bukan angka.
Dan juga (saya lupa meletakkan nomor cek bagian.), Ada fungsi memeriksa apakah string adalah angka atau tidak. Ini str.isdigit (). Ini sebuah contoh:
Jika Anda memanggil a.isdigit (), itu akan mengembalikan True.
sumber
2
diberikana
.