Як я можу перевірити, чи являє собою рядок int, не використовуючи спробуйте / крім?


466

Чи є спосіб визначити, чи являє собою рядок ціле число (наприклад '3', '-17'але немає '3.14'чи 'asfasfas'), не використовуючи механізм спробу / виключення?

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

23
Чому обидва намагаються зробити це "важким шляхом"? Що не так у спробі / крім?
S.Lott

5
Так, що не так із спробою / за винятком? Краще попросити пробачення, ніж дозволу.
mk12

53
Я б запитав, чому для цієї простої речі потрібно спробувати / хіба що? Система виключень - це складний звір, але це проста проблема.
Айвар

13
@Aivar припиніть поширювати FUD. Один спроб / крім блоку навіть не підходить до "складного".
Триптих

47
Це насправді не FUD. Ви будете ефективно писати 4 рядки коду, очікуючи, що щось підірветься, виберете цей виняток і зробите за замовчуванням, замість того, щоб використовувати один вкладиш.
andersonvom

Відповіді:


398

Якщо вас справді просто дратує використання try/excepts у всьому місці, будь ласка, просто напишіть функцію помічника:

def RepresentsInt(s):
    try: 
        int(s)
        return True
    except ValueError:
        return False

>>> print RepresentsInt("+123")
True
>>> print RepresentsInt("10.0")
False

Це буде НАЙКРАЩИЙ код, щоб точно покрити всі рядки, які Python вважає цілими числами. Я кажу, просто будьте пітонічним на цьому.


124
Тож вирішити просту задачу зі складним механізмом - пітонічно? Існує алгоритм виявлення записаної внутрішньої функції "int" int - я не бачу, чому це не виявляється як булева функція.
Айвар

79
@Aivar: Ця функція 5 рядків не є складним механізмом.
Триптих

34
За винятком:>>> print RepresentsInt(10.0) True >>> print RepresentsInt(10.06) True
Даннід

5
Я думаю, що це "пітонічно" в тому сенсі, що якщо Python вважає, що струна є цілою, то це робить і ваша програма. Якщо Python змінюється, це робить і ваша програма, і не змінюючи жодного рядка коду. У цьому є якась цінність. Це може бути правильним зробити в залежності від обставин.
Шавай

57
Я не знаю, чому це прийнята відповідь чи є так багато відгуків, оскільки це якраз протилежне тому, що просить ОП.
Безстрашний

755

з натуральними числами, які ви можете використовувати .isdigit:

>>> '16'.isdigit()
True

він не працює з негативними цілими числами. припустимо, ви можете спробувати наступне:

>>> s = '-17'
>>> s.startswith('-') and s[1:].isdigit()
True

він не працюватиме з '16.0'форматом, який подібний до intкастингу в цьому сенсі.

редагувати :

def check_int(s):
    if s[0] in ('-', '+'):
        return s[1:].isdigit()
    return s.isdigit()

6
це не справляється з "+17" без додаткового спеціального випадку.
Брайан Оуклі

1
Вам доведеться перевірити БОТИ випадки: lambda s: s.isdigit () або (s.startswith ('-') and s [1:]. Isdigit ())
грабувати

4
@Roberto: звичайно, слід! і я впевнений, що ти здатний на це!
SilentGhost

22
Примітка: u'²'.isdigit()вірно, але int(u'²')підвищує ValueError. Використовуйте u.isdecimal()замість цього. str.isdigit()є
локально

4
check_int('')підніме виняток замість поверненняFalse
wordbug

97

Ви знаєте, я виявив (і перевіряв це знову і знову), що спробувати / за винятком причин не працює все так добре. Я часто пробую кілька способів робити речі, і я не думаю, що я ніколи не знаходив метод, який використовує спробу / крім того, щоб виконати найкращі з перевірених, насправді мені здається, що ці методи зазвичай виходять близькими до найгірше, якщо не найгірше. Не в кожному випадку, але у багатьох випадках. Я знаю, що багато людей кажуть, що це "піфонічний" шлях, але це одна сфера, де я розлучаюся з ними. Для мене це не дуже ефектно і не дуже елегантно, тому я, як правило, використовую його лише для лову помилок та звітування.

Я збирався зрозуміти, що PHP, perl, ruby, C і навіть кричуща оболонка мають прості функції для тестування рядка для цілочистої кришки, але належна ретельність щодо перевірки цих припущень викликала мене! Мабуть, ця відсутність є звичайною хворобою.

Ось швидка та брудна редакція публікації Бруно:

import sys, time, re

g_intRegex = re.compile(r"^([+-]?[1-9]\d*|0)$")

testvals = [
    # integers
    0, 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:  return False
    return True

def isInt_str(v):
    v = str(v).strip()
    return v=='0' or (v if v.find('..') > -1 else v.lstrip('-+').rstrip('0').rstrip('.')).isdigit()

def isInt_re(v):
    import re
    if not hasattr(isInt_re, 'intRegex'):
        isInt_re.intRegex = re.compile(r"^([+-]?[1-9]\d*|0)$")
    return isInt_re.intRegex.match(str(v).strip()) is not None

def isInt_re2(v):
    return g_intRegex.match(str(v).strip()) is not None

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

Ось результати порівняння ефективності:

timings..
isInt_try:   0.6426
isInt_str:   0.7382
isInt_re:    1.1156
isInt_re2:   0.5344
check_int:   0.3452

Метод змінного струму міг би просканувати його один раз і зробити це. Метод змінного струму, який сканує рядок один раз, був би правильним питанням, я думаю.

Редагувати:

Я оновив вищевказаний код для роботи в Python 3.5 і включав функцію check_int із найбільш відповідної на даний момент відповіді, а також використовувати поточний найпопулярніший регулярний вираз, який я можу знайти для тестування на цілі численні кришки. Цей регулярний вираз відхиляє рядки типу "abc 123". Я додав 'abc 123' як тестове значення.

Мені дуже цікаво зазначити, що на даний момент НІКОЛЬ з перевірених функцій, включаючи метод спробу, популярну функцію check_int та найпопулярніший регулярний вираз для тестування на цілі чисили, повертають правильні відповіді на всі тестові значення (ну, залежно від того, на вашу думку, правильні відповіді; див. результати тесту нижче).

Вбудована функція int () мовчки обрізає дробову частину числа плаваючої точки і повертає цілу частину перед десятковою, якщо тільки номер плаваючої точки спочатку не перетворюється на рядок.

Функція check_int () повертає false для значень, таких як 0,0 та 1,0 (які технічно є цілими числами) і повертає true для значень типу "06".

Ось поточні результати (Python 3.5) тесту:

                  isInt_try |       isInt_str       |       isInt_re        |       isInt_re2       |   check_int   |
    0               True    |               True    |               True    |               True    |       True    |
    1               True    |               True    |               True    |               True    |       True    |
    -1              True    |               True    |               True    |               True    |       True    |
    1.0             True    |               True    |               False   |               False   |       False   |
    -1.0            True    |               True    |               False   |               False   |       False   |
    '0'             True    |               True    |               True    |               True    |       True    |
    '0.'            False   |               True    |               False   |               False   |       False   |
    '0.0'           False   |               True    |               False   |               False   |       False   |
    '1'             True    |               True    |               True    |               True    |       True    |
    '-1'            True    |               True    |               True    |               True    |       True    |
    '+1'            True    |               True    |               True    |               True    |       True    |
    '1.0'           False   |               True    |               False   |               False   |       False   |
    '-1.0'          False   |               True    |               False   |               False   |       False   |
    '+1.0'          False   |               True    |               False   |               False   |       False   |
    '06'            True    |               True    |               False   |               False   |       True    |
    'abc 123'       False   |               False   |               False   |               False   |       False   |
    1.1             True    |               False   |               False   |               False   |       False   |
    -1.1            True    |               False   |               False   |               False   |       False   |
    '1.1'           False   |               False   |               False   |               False   |       False   |
    '-1.1'          False   |               False   |               False   |               False   |       False   |
    '+1.1'          False   |               False   |               False   |               False   |       False   |
    '1.1.1'         False   |               False   |               False   |               False   |       False   |
    '1.1.0'         False   |               False   |               False   |               False   |       False   |
    '1.0.1'         False   |               False   |               False   |               False   |       False   |
    '1.0.0'         False   |               False   |               False   |               False   |       False   |
    '1.0.'          False   |               False   |               False   |               False   |       False   |
    '1..0'          False   |               False   |               False   |               False   |       False   |
    '1..'           False   |               False   |               False   |               False   |       False   |
    '0.0.'          False   |               False   |               False   |               False   |       False   |
    '0..0'          False   |               False   |               False   |               False   |       False   |
    '0..'           False   |               False   |               False   |               False   |       False   |
    'one'           False   |               False   |               False   |               False   |       False   |
    <obj..>         False   |               False   |               False   |               False   |       False   |
    (1, 2, 3)       False   |               False   |               False   |               False   |       False   |
    [1, 2, 3]       False   |               False   |               False   |               False   |       False   |
    {'one': 'two'}  False   |               False   |               False   |               False   |       False   |
    ' 0 '           True    |               True    |               True    |               True    |       False   |
    ' 0.'           False   |               True    |               False   |               False   |       False   |
    ' .0'           False   |               False   |               False   |               False   |       False   |
    '.01 '          False   |               False   |               False   |               False   |       False   |

Щойно я спробував додати цю функцію:

def isInt_float(s):
    try:
        return float(str(s)).is_integer()
    except:
        return False

Він працює майже так само, як і check_int (0,3486), і повертає істинні значення, такі як 1,0 і 0,0, +1,0 і 0, .0 і так далі. Але це також повертає істину для "06", так Збирай свою отруту, гадаю.


Можливо, його частина походить від того, що ціле число є трохи довільним. Система програмування не може прийняти розкіш, якщо припустити, що це завжди десяткове представлення. 0x4df, в деяких місцях є дійсним цілим числом, а в інших - 0891. Я боявся подумати, що може виникнути при такому перевірці unicode.
PlexQ

3
+1 за час. Я згоден, що весь цей винятковий бізнес не дуже елегантний для такого простого питання. Ви очікуєте побудови допоміжного методу для такої поширеної проблеми ...
RickyA

9
Я знаю, що ця тема в основному не працює, але +1 для врахування часу виконання. Довжина рядка не завжди вказує на основну складність; і звичайно, спробувати / за винятком може виглядати простий (і читати легко, що теж важливо), але це є дорогою операцією. Я заперечую, що ієрархія уподобань завжди повинна виглядати приблизно так: 1. Просте читання явного рішення (SilentGhost's). 2. Легке для читання неявне рішення (триптих). 3. Немає трьох.
Ерік Хамфрі

1
Дякуємо за ваші глибокі розслідування щодо такої, здавалося б, незначної теми. Я піду з isInt_str (), пітонічним чи ні. Що мене нудить, це те, що я не знайшов нічого про значення v.find ('..'). Це якийсь особливий синтаксис знахідки чи крайній регістр числового рядка?
JackLeEmmerdeur

3
Так, трохи застарілий, але все-таки дійсно приємний і відповідний аналіз. У Python 3.5 tryефективніше: isInt_try: 0.6552 / isInt_str: 0.6396 / isInt_re: 1.0296 / isInt_re2: 0.5168.
Дейв

39

str.isdigit() повинен зробити трюк.

Приклади:

str.isdigit("23") ## True
str.isdigit("abc") ## False
str.isdigit("23.4") ## False

EDIT : Як зазначав @BuzzMoschetti, цей спосіб не матиме мінусового числа (наприклад, "-23" ). Якщо ваш input_num може бути меншим за 0, використовуйте re.sub (regex_search, regex_replace, content) перед застосуванням str.isdigit () . Наприклад:

import re
input_num = "-23"
input_num = re.sub("^-", "", input_num) ## "^" indicates to remove the first "-" only
str.isdigit(input_num) ## True

1
Тому що -23 дає хибність.
Buzz Moschetti

1
@BuzzMoschetti ти маєш рацію. Швидкий спосіб виправити - це видалення знака мінус шляхом повторної заміни (regex_search, regex_replace, content) перед нанесенням str.isdigit ()
Catbuilts

27

Використовуйте регулярний вираз:

import re
def RepresentsInt(s):
    return re.match(r"[-+]?\d+$", s) is not None

Якщо ви також повинні прийняти десяткові дроби, також:

def RepresentsInt(s):
    return re.match(r"[-+]?\d+(\.0*)?$", s) is not None

Щоб покращити продуктивність, якщо ви робите це часто, компілюйте регулярний вираз лише один раз, використовуючи re.compile().


19
+1: виявляє, що це жахливо складно і дорого в порівнянні з спробою / за винятком.
С.Лотт

2
Я вважаю, що це, по суті, більш повільна, спеціальна версія рішення "Інімеру", запропонована @SilentGhost.
Грег

@Greg: Оскільки @SilentGhost неправильно висвітлює знаки, ця версія фактично працює.
С.Лотт

1
@ S.Lott: безумовно, кожен, хто здатний розміщувати повідомлення на SO, міг би розширити мій приклад на прикриття знаків.
SilentGhost

2
регулярні вислови стосуються найскладнішої та незрозумілої речі, що я існує, я вважаю, що проста перевірка вище є суттєво зрозумілішою, навіть якщо я вважаю, що це все ще негарно, це потворніше.
PlexQ

18

Правильне рішення RegEx поєднало б ідеї Грега Хьюгілла та Ноуелла, але не використовувало глобальну змінну. Ви можете досягти цього, приєднавши атрибут до методу. Крім того, я знаю, що нахмуритися вводити імпорт методом, але те, що я збираюся, - це ефект "ледачого модуля", як http://peak.telecommunity.com/DevCenter/Importing#lazy-imports

редагувати: Моя улюблена методика поки що - використовувати виключно методи об’єкта String

#!/usr/bin/env python

# Uses exclusively methods of the String object
def isInteger(i):
    i = str(i)
    return i=='0' or (i if i.find('..') > -1 else i.lstrip('-+').rstrip('0').rstrip('.')).isdigit()

# Uses re module for regex
def isIntegre(i):
    import re
    if not 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)) is not None

# When executed directly run Unit Tests
if __name__ == '__main__':
    for obj in [
                # integers
                0, 1, -1, 1.0, -1.0,
                '0', '0.','0.0', '1', '-1', '+1', '1.0', '-1.0', '+1.0',
                # non-integers
                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'}
            ]:
        # 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 output
        if isinstance(obj, str):
            obj = ("'%s'" % (obj,))
        print("%30s is %14s is %14s" % (obj, integer, integre))

А для менш пригодних членів класу ось результат:

I compile only once. Remove this line when you are confident in that.
                             0 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
                           '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.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' 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

4
Я погоджуся, що мій тестовий набір є надмірним. Мені подобається доводити, що мій код працює, коли я його пишу. Але чи вважаєте ви, що моя функція isInteger є надмірною? Напевно ні.
Бруно Броноський,

1
Я щойно проголосував проти, без коментарів. Що з людьми? Я розумію, що тисячоліття зараз використовують "Лайки" як "читати квитанції". Але чи використовують вони зараз маркери як "не метод, який я вибрав"? Можливо, вони не усвідомлюють, що вона віднімає 2 бали від власної репутації, щоб голосувати за відповідь. SO / SE робить це для того, щоб заохочувати голосувати лише через дезінформацію, і тоді я сподіваюся, що ви залишите коментар .
Бруно Броноський

5
>>> "+7".lstrip("-+").isdigit()
True
>>> "-7".lstrip("-+").isdigit()
True
>>> "7".lstrip("-+").isdigit()
True
>>> "13.4".lstrip("-+").isdigit()
False

Отже, вашою функцією було б:

def is_int(val):
   return val[1].isdigit() and val.lstrip("-+").isdigit()

1
is_int ("2") підвищує IndexError.
anttikoo

4

У підході Грега Хьюгілла бракувало декількох компонентів: провідний "^", щоб відповідати лише початку рядка, і попередньо складати повторно. Але такий підхід дозволить вам уникнути спроби: exept:

import re
INT_RE = re.compile(r"^[-]?\d+$")
def RepresentsInt(s):
    return INT_RE.match(str(s)) is not None

Мені було б цікаво, чому ви намагаєтеся уникати спроб: хіба що?


1
Справа стилю. Я думаю, що "пробувати / виключати" слід використовувати лише з фактичними помилками, а не з нормальним потоком програми.
Адам Матан

2
@Udi Pasmon: Python досить широко використовує спробу / за винятком "нормального" потоку програми. Наприклад, кожен ітератор зупиняється з підвищеним винятком.
С.Лотт

3
-1: Хоча ваш натяк на компіляцію регулярного виразу правильний, ви помиляєтесь, критикуючи Грега в іншому відношенні: re.match відповідає проти початку рядка, тому ^ у шаблоні насправді зайвий. (Це відрізняється, коли використовується повторний пошук).
ThomasH

С.Лотт - Чи вважається це розумним потоком в пітоні? Чим це відрізняється від інших мов? Можливо, варто окремого питання.
Адам Матан

1
Сильне використання спробу / крім Python було розглянуто тут на SO. Спробуйте шукати "[python] за винятком"
S.Lott

4

Я повинен робити це постійно, і у мене є легка, але, очевидно, ірраціональна відраза до використання спроби / за винятком шаблону. Я використовую це:

all([xi in '1234567890' for xi in x])

Він не містить від'ємних чисел, тому ви можете викреслити один знак мінус (якщо такий є), а потім перевірити, чи містить результат цифри від 0 до 9:

all([xi in '1234567890' for xi in x.replace('-', '', 1)])

Ви також можете передати x до str (), якщо не впевнені, що введення є рядком:

all([xi in '1234567890' for xi in str(x).replace('-', '', 1)])

Є щонайменше два (крайні?) Випадки, коли це розпадається:

  1. Це не працює для різних наукових та / або експоненціальних позначень (наприклад, 1.2E3, 10 ^ 3 тощо) - і те й інше поверне помилкове. Я не думаю, що інші відповіді це також не відповідають, і навіть Python 3.8 не суперечить думкам, оскільки type(1E2)дає, <class 'float'>хоча type(10^2)дає<class 'int'> .
  2. Порожній рядок вводить True.

Таким чином, він не працюватиме для кожного можливого введення, але якщо ви можете виключити наукові позначення, експоненціальні позначення та порожні рядки, це однорядкова перевірка ОК, яка повертається, Falseякщо x не є цілим числом іTrue якщо x - цілим числом.

Я не знаю, чи це пітонічно, але це один рядок, і відносно зрозуміло, що робить код.


Спробуйте / крім, схоже, ходити на чиюсь галявину (спробувати), і тоді, коли / коли вони помічають і сердяться (виняток), ви вибачаєтесь (обробляйте виняток), тоді як мій all(xi in '1234567890' for xi in x])зразок здається більше схожим на прохання дозволу ходити по газоні. Я не в захваті від запитувача дозволу, але ось ми.
mRotten

3

я думаю

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

було б краще переписати на:

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

тому що s [1:] також створює новий рядок

Але набагато краще рішення

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

3
Вгадайте, що replaceробить? Також це неправильно прийме 5-2, наприклад.
Ри-

Викине IndexError, якщоs='-'
Анти Земля

s = '-'; s.replace ('-', '') .isdigit () -> Неправдиво
Владислав Савченко

2

Мені дуже сподобався пост Шаве, але я додав ще один тестовий випадок (і вбудовану функцію 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()

і це значно послідовно перемагає часи решти:

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

використовуючи звичайний 2,7 пітон:

$ python --version
Python 2.7.10

Обидва два тестових випадки, які я додав (isInt_loop та isInt_digit), проходять абсолютно однакові тестові випадки (вони обидва приймають лише непідписані цілі числа), але я вважав, що люди можуть бути більш розумні з модифікацією реалізації рядка (isInt_loop) на противагу вбудованому в isdigit () функцію, тому я включив її, хоча незначна різниця у часі виконання. (і обидва способи багато чого перемогли, але не обробляйте зайві речі: "./+/-")

Крім того, мені було цікаво відзначити, що регекс (метод isInt_re2) переміг порівняння рядків у тому ж тесті, який виконував Шавай у 2012 році (наразі 2018). Може бути покращено бібліотеки регулярних виразів?


1

На мою думку, це, мабуть, найпростіший і пітонічний спосіб наблизитись до цього. Я не бачив цього рішення, і це в основному те саме, що і регулярний вираз, але без регулярного вираження.

def is_int(test):
    import string
    return not (set(test) - set(string.digits))

set(input_string) == set(string.digits)якщо ми пропустимо '-+ 'на початку і.0 , E-1врешті-решт.
jfs

1

Ось функція, яка аналізує, не викликаючи помилок. Він обробляє очевидні випадки повернення Noneпри відмові (обробляє до 2000 знаків '- / +' за замовчуванням на 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)

Деякі тести:

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

Результати:

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

Для своїх потреб ви можете використовувати:

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

1

Я пропоную наступне:

import ast

def is_int(s):
    return isinstance(ast.literal_eval(s), int)

З документів :

Безпечно оцініть вузол виразів або рядок, що містить літерал Python або відображення контейнера. Наданий рядок або вузол може складатися лише з таких буквальних структур Python: рядки, байти, числа, кортежі, списки, дикти, набори, булеві і None.

Слід зазначити, що це призведе до ValueErrorвинятку, коли закликається проти чогось, що не є літералом Python. Оскільки в запитанні було запропоновано рішення без спроб / крім, у мене є рішення типу Kobayashi-Maru для цього:

from ast import literal_eval
from contextlib import suppress

def is_int(s):
    with suppress(ValueError):
        return isinstance(literal_eval(s), int)
    return False

¯ \ _ (ツ) _ / ¯


0

У мене є одна можливість, яка взагалі не використовує int, і не повинна створювати виняток, якщо рядок не представляє число

float(number)==float(number)//1

Він повинен працювати для будь-якого типу рядка, який плаває, приймає, позитивні, негативні, інженерні позначення ...


0

Я думаю, що питання пов'язане зі швидкістю, оскільки спроба / за винятком часового покарання:

 дані тесту

По-перше, я створив список з 200 рядків, 100 відмовних рядків і 100 числових рядків.

from random import shuffle
numbers = [u'+1'] * 100
nonumbers = [u'1abc'] * 100
testlist = numbers + nonumbers
shuffle(testlist)
testlist = np.array(testlist)

 numpy рішення (працює лише з масивами та unicode)

np.core.defchararray.isnumeric також може працювати з рядками Unicode, np.core.defchararray.isnumeric(u'+12')але він повертається та масив. Тож, це гарне рішення, якщо вам доведеться зробити тисячі перетворень і відсутні дані або не числові дані.

import numpy as np
%timeit np.core.defchararray.isnumeric(testlist)
10000 loops, best of 3: 27.9 µs per loop # 200 numbers per loop

спробуйте / крім

def check_num(s):
  try:
    int(s)
    return True
  except:
    return False

def 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

Здається, що нудотне рішення набагато швидше.


0

Якщо ви бажаєте приймати лише цифри з нижчим рівнем асції, ось такі тести:

Python 3.7+: (u.isdecimal() and u.isascii())

Python <= 3,6: (u.isdecimal() and u == str(int(u)))

Інші відповіді пропонують використовувати .isdigit()або, .isdecimal()але вони включають деякі символи верхнього унікоду, такі як '٢'( u'\u0662'):

u = u'\u0662'     # '٢'
u.isdigit()       # True
u.isdecimal()     # True
u.isascii()       # False (Python 3.7+ only)
u == str(int(u))  # False

Це не буде обробляти негативні значення або пробіли з пробілами, обидва з яких обробляються просто чудово int().
ShadowRanger

-6

Спробуйте.

def int_check(a):
    if int(a) == a:
        return True
    else:
        return False

Це працює, якщо ви не ставите рядок, який не є числом.

А також (я забув покласти частину перевірки числа.), Є перевірка функції, чи рядок є числом чи ні. Це str.isdigit (). Ось приклад:

a = 2
a.isdigit()

Якщо ви зателефонуєте на a.isdigit (), він поверне значення True.


Я думаю, вам потрібні лапки навколо значення, 2призначеного a.
Люк Вудвард

1
Чому це не головна відповідь? Це точно відповідає на питання.
коник

6
-1 питання: "Перевірте, чи рядок являє собою цілу точку, не використовуючи спробувати / крім?" для @Caroline Alexiou
jfs
Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.