733 Stimmen

Wie kann ich überprüfen, ob eine Zeichenfolge eine int darstellt, ohne try/except zu verwenden?

Kann man irgendwie feststellen, ob ein String steht für eine ganze Zahl (z.B., '3' , '-17' aber nicht '3.14' o 'asfasfas' ) Ohne Verwendung eines try/except-Mechanismus?

is_int('3.14') == False
is_int('-7')   == True

28 Stimmen

Warum versuchen beide, dies "auf die harte Tour" zu tun? Was ist falsch an try/except?

8 Stimmen

Ja, was ist falsch an try/except? Es ist besser, um Vergebung zu bitten als um Erlaubnis.

82 Stimmen

Ich würde fragen, warum sollte diese einfache Sache try/except erfordern? Das Ausnahmesystem ist ein komplexes Biest, aber dies ist ein einfaches Problem.

5voto

SuperNova Punkte 20412

Sie können die nachstehende Methode zur Überprüfung verwenden.

def check_if_string_is_int(string1):
    for character in string1:
        if not character.isdigit():
            return "Not a number"
    else:
        return "Is a number"

5voto

Ich denke

s.startswith('-') and s[1:].isdigit()

sollte besser umgeschrieben werden:

s.replace('-', '').isdigit()

denn s[1:] erzeugt auch eine neue Zeichenkette

Eine viel bessere Lösung ist jedoch

s.lstrip('+-').isdigit()

3voto

Konstantin Smolyanin Punkte 15905

Vorbedingungen:

  • es handelt sich um ganze Zahlen (nicht um Dezimalzahlen/Floats);
  • Verhalten der eingebauten int() ist ein Standard für uns (manchmal ist es seltsam: "-00" ist die richtige Eingabe dafür)

Kurze Antwort:

Verwenden Sie den folgenden Code. Er lautet einfach , richtig (während viele Varianten in diesem Thread es nicht sind) und fast übertrifft zweimal die Leistung beide try/except y regex Varianten.

def is_int_str(string):
    return (
        string.startswith(('-', '+')) and string[1:].isdigit()
    ) or string.isdigit()

TL;DR Antwort:

Ich habe 3 Hauptvarianten getestet (1) try/except, (2) re.match() und (3) String-Operationen (siehe oben). Die dritte Variante ist etwa doppelt so schnell wie beide try/except y re.match() . Übrigens: Die Regex-Variante ist am langsamsten! Siehe Testskript unten.

import re
import time

def test(func, test_suite):
    for test_case in test_suite:
        actual_result = func(*test_case[0])
        expected_result = test_case[1]
        assert (
            actual_result == expected_result
        ), f'Expected: {expected_result} but actual: {actual_result}'

def perf(func, test_suite):
    start = time.time()

    for _ in range(0, 1_000_000):
        test(func, test_suite)

    return time.time() - start

def is_int_str_1(string):
    try:
        int(string)
        return True
    except ValueError:
        return False

def is_int_str_2(string):
    return re.match(r'^[\-+]?\d+$', string) is not None

def is_int_str_3(string):
    return (
        string.startswith(('-', '+')) and string[1:].isdigit()
    ) or string.isdigit()

# Behavior of built-in int() function is a standard for the following tests
test_suite = [
    [['1'], True],  # func('1') -> True
    [['-1'], True],
    [['+1'], True],
    [['--1'], False],
    [['++1'], False],
    [['001'], True],  # because int() can read it
    [['-00'], True],  # because of quite strange behavior of int()
    [['-'], False],
    [['abracadabra'], False],
    [['57938759283475928347592347598357098458405834957984755200000000'], True],
]

time_span_1 = perf(is_int_str_1, test_suite)
time_span_2 = perf(is_int_str_2, test_suite)
time_span_3 = perf(is_int_str_3, test_suite)

print(f'{is_int_str_1.__name__}: {time_span_1} seconds')
print(f'{is_int_str_2.__name__}: {time_span_2} seconds')
print(f'{is_int_str_3.__name__}: {time_span_3} seconds')

Die Ausgabe war:

is_int_str_1: 4.314162969589233 seconds
is_int_str_2: 5.7216269969940186 seconds
is_int_str_3: 2.5828163623809814 seconds

2voto

brw59 Punkte 492

Der Beitrag von Shavais hat mir sehr gut gefallen, aber ich habe noch einen weiteren Testfall hinzugefügt ( & die eingebaute Funktion isdigit()):

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 not in numbers:
            return False
    return True

def isInt_Digit(v):
    v = str(v).strip()
    return v.isdigit()

und sie schlägt die Zeiten der anderen deutlich:

timings..
isInt_try:   0.4628
isInt_str:   0.3556
isInt_re:    0.4889
isInt_re2:   0.2726
isInt_loop:   0.1842
isInt_Digit:   0.1577

mit normalem 2.7er Python:

$ python --version
Python 2.7.10

Die beiden von mir hinzugefügten Testfälle (isInt_loop und isInt_digit) bestehen genau die gleichen Testfälle (beide akzeptieren nur ganze Zahlen ohne Vorzeichen), aber ich dachte, dass die Leute die String-Implementierung (isInt_loop) geschickter ändern könnten als die eingebaute isdigit()-Funktion, also habe ich sie mit einbezogen, obwohl es einen kleinen Unterschied in der Ausführungszeit gibt. (und beide Methoden schlagen alles andere um Längen, behandeln aber die zusätzlichen Dinge nicht: "./+/-" )

Außerdem fand ich es interessant festzustellen, dass der Regex (isInt_re2-Methode) den String-Vergleich im selben Test, der 2012 von Shavais durchgeführt wurde (aktuell 2018), geschlagen hat. Vielleicht sind die Regex-Bibliotheken verbessert worden?

1voto

Reut Sharabani Punkte 28873

Hier ist eine Funktion, die keine Fehler auslöst. Sie behandelt offensichtliche Fälle und gibt None bei Fehlschlag (verarbeitet standardmäßig bis zu 2000 '-/+'-Zeichen in CPython!):

#!/usr/bin/env python

def get_int(number):
    splits = number.split('.')
    if len(splits) > 2:
        # too many splits
        return None
    if len(splits) == 2 and splits[1]:
        # handle decimal part recursively :-)
        if get_int(splits[1]) != 0:
            return None

    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)

Einige Tests:

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

Ergebnisse:

get_int(0) = 0
get_int(0.0) = 0
get_int(0.1) = None
get_int(1) = 1
get_int(1.1) = None
get_int(1.0) = 1
get_int(-1) = -1
get_int(-1.1) = None
get_int(-1.0) = -1
get_int(-0) = 0
get_int(--0) = 0
get_int(---3) = -3
get_int(.3) = None
get_int(--3.) = 3
get_int(+13) = 13
get_int(+-1.00) = -1
get_int(--+123) = 123
get_int(-0.000) = 0

Für Ihre Bedürfnisse können Sie verwenden:

def int_predicate(number):
     return get_int(number) is not None

CodeJaeger.com

CodeJaeger ist eine Gemeinschaft für Programmierer, die täglich Hilfe erhalten..
Wir haben viele Inhalte, und Sie können auch Ihre eigenen Fragen stellen oder die Fragen anderer Leute lösen.

Powered by:

X