Verallgemeinertes Integer-Casting in Python

8

Hintergrund

Ich habe eine Zeichenfolge in Python, die ich in eine Ganzzahl konvertieren möchte. Normalerweise würde ich nur verwenden int:

>>> int("123")
123

Leider ist diese Methode nicht sehr robust, da nur übereinstimmende Zeichenfolgen akzeptiert werden -?[0-9]+(nachdem alle führenden oder nachfolgenden Leerzeichen entfernt wurden). Beispielsweise kann es keine Eingabe mit einem Dezimalpunkt verarbeiten:

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

Und damit kann es sicher nicht umgehen:

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

Auf der anderen Seite kann genau dieses Verhalten in Perl, PHP und sogar im bescheidenen QBasic ohne viel Aufhebens beobachtet werden:

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

Frage

Hier ist meine kürzeste Anstrengung bei dieser "Verallgemeinerung int" in Python. Es sind 50 Bytes, vorausgesetzt, die ursprüngliche Zeichenfolge befindet sich in sund das Ergebnis sollte enden in i:

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

Ziemlich einfach, aber das try/ exceptbit ist hässlich und lang. Gibt es eine Möglichkeit, es zu verkürzen?

Einzelheiten

Die Antworten müssen alle folgenden Schritte ausführen:

  • Beginnen Sie mit einem String in s; ende mit seinem ganzzahligen Wert in i.
  • Die Ganzzahl ist der erste Ziffernlauf in der Zeichenfolge. Alles danach wird ignoriert, einschließlich anderer Ziffern, wenn sie nach Nicht-Ziffern kommen.
  • Führende Nullen in der Eingabe sind gültig.
  • Jede Zeichenfolge, die nicht mit einer gültigen Ganzzahl beginnt, hat den Wert von 0.

Die folgenden Funktionen werden bevorzugt , sind jedoch nicht erforderlich:

  • Ein einzelnes -Vorzeichen unmittelbar vor den Ziffern macht die Ganzzahl negativ.
  • Ignoriert Leerzeichen vor und nach der Nummer.
  • Funktioniert genauso gut in Python 2 oder 3.

(Hinweis: Mein obiger Code erfüllt alle diese Kriterien.)

Testfälle

"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
quelle
Etwas verwandt: codegolf.stackexchange.com/questions/28783/… (aber dort wurde ausdrücklich angegeben, dass die Eingabe richtig geformte ganze Zahlen sein würden).
DLosc
1
Was soll "12abc3"geben?
Orlp
@orlp 12- es ist analog zum "123.45"Fall.
DLosc
(lambda(x)(or(parse-integer x :junk-allowed t)0))(Common Lisp, 49 Byte) - Wird nur als Kommentar gepostet, da es integriert ist.
Coredump
1
@coredump :junk-allowed--ha, das ist großartig! Ich hätte dies zu einer allgemeinen Golfherausforderung gemacht, wenn die Antwort in vielen Sprachen nicht trivial gewesen wäre. Aber danke für das Lisp. : ^)
DLosc

Antworten:

4

40 Bytes

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

und Sie können Negative für 8 Zeichen mehr machen:

import re;i=int((re.findall("^-?\d+",s)+[0])[0])
KSab
quelle
@ DLosc Ah du hast recht, habe den zweiten anscheinend nicht gut genug getestet. Der 'Aha'-Moment war, als ich realisierte, dass einige Python-Regex-Funktionen Strings zurückgeben, nicht MatchObjects
KSab
1
import re;i=int((re.findall("^-?\d+",s)+[0])[0])funktioniert für 48 Bytes.
DLosc
6

Python 2, 47 , 46

Es ist nicht so kurz wie die Verwendung von Regex, aber ich fand es unterhaltsam dunkel.

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

-1 aufgrund von KSab - strmit einigen großen Ganzzahlen funktioniert besser als der Repr-Operator, da er kein Lam Ende setzt.

Feersum
quelle
2
Sie können ein Byte rasieren, indem Sie str(1<<68)im lstrip
KSab
Beeindruckend. Unterhaltsam dunkel ist richtig! (Dies behandelt nur nichtnegative Zahlen, richtig?)
DLosc
Ein weiterer Bonus von @ KSabs Vorschlag ist die Python 3-Kompatibilität.
DLosc