Casting integer umum dengan Python

8

Latar Belakang

Saya memiliki string dengan Python yang ingin saya konversi menjadi integer. Biasanya, saya hanya akan menggunakan int:

>>> int("123")
123

Sayangnya, metode ini tidak terlalu kuat, karena hanya menerima string yang cocok -?[0-9]+(setelah menghapus spasi spasi awal atau akhir). Misalnya, tidak dapat menangani input dengan titik desimal:

>>> int("123.45")
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
ValueError: invalid literal for int() with base 10: '123.45'

Dan tentu saja tidak bisa menangani ini:

>>> int("123abc?!")

Di sisi lain, perilaku ini sebenarnya bisa didapat tanpa keributan dalam Perl, PHP, dan bahkan QBasic yang sederhana:

INT(VAL("123abc"))   ' 123

Pertanyaan

Inilah upaya terpendek saya untuk "generalisasi int" ini dengan Python. Ini 50 byte, dengan asumsi bahwa string asli dalam sdan hasilnya akan berakhir pada i:

n="";i=0
for c in s:
 n+=c
 try:i=int(n)
 except:0

Cukup mudah, tapi try/ exceptbit jelek dan panjang. Apakah ada cara untuk mempersingkatnya?

Detail

Jawaban perlu melakukan semua hal berikut:

  • Mulai dengan string s; diakhiri dengan nilai integer pada i.
  • Bilangan bulat adalah angka pertama yang dijalankan dalam string. Semuanya setelah itu diabaikan, termasuk digit lainnya jika mereka datang setelah non-digit.
  • Angka nol di input valid.
  • Setiap string yang tidak dimulai dengan integer yang valid memiliki nilai 0.

Fitur-fitur berikut lebih disukai , meskipun tidak diperlukan:

  • Satu -tanda segera sebelum digit membuat bilangan bulat negatif.
  • Abaikan spasi putih sebelum dan sesudah nomor.
  • Bekerja sama baiknya di Python 2 atau 3.

(Catatan: kode saya di atas memenuhi semua kriteria ini.)

Uji kasus

"0123"   -> 123
"123abc" -> 123
"123.45" -> 123
"abc123" -> 0
"-123"   -> -123 (or 0 if negatives not handled)
"-1-2"   -> -1 (or 0 if negatives not handled)
"--1"    -> 0
""       -> 0
DLosc
sumber
Agak terkait: codegolf.stackexchange.com/questions/28783/… (tetapi di sana secara eksplisit dinyatakan bahwa input akan menjadi bilangan bulat yang dibentuk dengan benar).
DLosc
1
Apa yang seharusnya "12abc3"memberi?
orlp
@ orlp - 12ini analog dengan "123.45"case.
DLosc
(lambda(x)(or(parse-integer x :junk-allowed t)0))(Common Lisp, 49 bytes) - Hanya diposkan sebagai komentar karena sudah built-in.
coredump
1
@coredump :junk-allowed--ha, bagus sekali! Saya akan menjadikan ini tantangan golf umum, kalau bukan karena fakta bahwa jawaban dalam banyak bahasa itu sepele. Tapi terima kasih untuk Lisp. : ^)
DLosc

Jawaban:

4

40 byte

import re;i=int("0"+re.split("\D",s)[0])

dan Anda dapat melakukan negatif untuk 8 karakter lebih banyak:

import re;i=int((re.findall("^-?\d+",s)+[0])[0])
KSab
sumber
@Doscosc Ah kau benar, ternyata tidak menguji yang kedua dengan cukup baik. Momen 'aha' adalah ketika saya menyadari beberapa fungsi python regex mengembalikan string yang bukan MatchObjects
KSab
1
import re;i=int((re.findall("^-?\d+",s)+[0])[0])berfungsi, selama 48 byte.
DLosc
6

Python 2, 47 , 46

Ini tidak sesingkat menggunakan regex, tapi saya pikir itu menghibur tidak jelas.

i=int(('0%sx'%s)[:~len(s.lstrip(str(1<<68)))])

-1 karena KSab - strdengan beberapa bilangan bulat besar bekerja lebih baik daripada operator repr karena tidak menempatkan Lpada akhirnya.

feersum
sumber
2
Anda dapat mencukur byte dengan menggunakan str(1<<68)di dalam lstrip
KSab
Wow. Menghibur jelas benar! (Ini hanya menangani nomor non-negatif, benar?)
DLosc
Bonus lain dari saran @ KSab adalah kompatibilitas Python 3.
DLosc