python - كيف أتحقق من أن السلسلة عبارة عن رقم(عائم)؟



casting floating-point type-conversion (25)

فعلت بعض اختبار السرعة. دعنا نقول أنه إذا كان من المرجح أن يكون الرقم هو رقم المحاولة / الاستثناء هو أسرع ما يمكن.إذا كان من غير المحتمل أن يكون الرقم رقمًا وكنت مهتمًا بفحص Integer ، فإنه يستحق القيام ببعض الاختبارات (isdigit plus العنوان '-'). إذا كنت مهتمًا بالتحقق من رقم عائم ، فعليك استخدام ميزة try / except code whitout escape.

ما هي أفضل طريقة ممكنة للتحقق مما إذا كان يمكن تمثيل السلسلة كرقم في بايثون؟

الوظيفة التي لدي حاليا هي:

def is_number(s):
    try:
        float(s)
        return True
    except ValueError:
        return False

الذي ، ليس فقط بشع وبطيء ، يبدو عالي الكعب. ومع ذلك لم أجد طريقة أفضل لأن استدعاء float في الوظيفة الرئيسية هو أسوأ من ذلك.


للاستخدام int هذا:

>>> "1221323".isdigit()
True

ولكن بالنسبة float نحن بحاجة إلى بعض الحيل ؛-). كل رقم عائم له نقطة واحدة ...

>>> "12.34".isdigit()
False
>>> "12.34".replace('.','',1).isdigit()
True
>>> "12.3.4".replace('.','',1).isdigit()
False

أيضا للأرقام السالبة فقط lstrip() :

>>> '-12'.lstrip('-')
'12'

والآن نحصل على طريقة عالمية:

>>> '-12.34'.lstrip('-').replace('.','',1).isdigit()
True
>>> '.-234'.lstrip('-').replace('.','',1).isdigit()
False

I was working on a problem that led me to this thread, namely how to convert a collection of data to strings and numbers in the most intuitive way. I realized after reading the original code that what I needed was different in two ways:

1 - I wanted an integer result if the string represented an integer

2 - I wanted a number or a string result to stick into a data structure

so I adapted the original code to produce this derivative:

def string_or_number(s):
    try:
        z = int(s)
        return z
    except ValueError:
        try:
            z = float(s)
            return z
        except ValueError:
            return s

رمزك يبدو جيدًا بالنسبة لي.

ربما كنت تعتقد أن الشفرة "عالية الكعب" بسبب استخدام الاستثناءات؟ لاحظ أن مبرمجي بايثون يميلون إلى استخدام الاستثناءات بشكل حر عندما يحسن قراءة الكود ، وذلك بفضل جزاء الأداء المنخفض.


توفر هذه الإجابة دليل خطوة بخطوة يحتوي على وظيفة مع أمثلة للعثور على السلسلة:

  • عدد صحيح موجب
  • موجب / سلبي - عدد صحيح / عائم
  • كيفية تجاهل الجمل "NaN" (وليس رقمًا) أثناء التحقق من الرقم؟

تحقق مما إذا كانت السلسلة عبارة عن عدد صحيح موجب

يمكنك استخدام isdigit() للتحقق ما إذا كانت سلسلة المعطى عددًا صحيحًا موجبًا .

نتائج العينة:

# For digit
>>> '1'.isdigit()
True
>>> '1'.isalpha()
False

تحقق من وجود سلسلة موجبة / سلبية - عدد صحيح / عدد عشري

str.isdigit() بإرجاع False إذا كانت السلسلة رقم سالب أو رقم عائم. فمثلا:

# returns `False` for float
>>> '123.3'.isdigit()
False
# returns `False` for negative number
>>> '-123'.isdigit()
False

إذا كنت تريد أيضًا التحقق من الأعداد الصحيحة والسلبية ، فيمكنك كتابة وظيفة مخصصة للتحقق منها على النحو التالي:

def is_number(n):
    try:
        float(n)   # Type-casting the string to `float`.
                   # If string is not a valid `float`, 
                   # it'll raise `ValueError` exception
    except ValueError:
        return False
    return True

نموذج تشغيل:

>>> is_number('123')    # positive integer number
True

>>> is_number('123.4')  # positive float number
True

>>> is_number('-123')   # negative integer number
True

>>> is_number('-123.4') # negative `float` number
True

>>> is_number('abc')    # `False` for "some random" string
False

تجاهل السلاسل "NaN" (ليست رقمًا) أثناء التحقق من الرقم

ستقوم الدالات أعلاه بإرجاع True لسلسلة "NAN" (ليست رقمًا) نظرًا لأن python عبارة عن عوامة صحيحة تمثل أنها ليست رقمًا. فمثلا:

>>> is_number('NaN')
True

لمعرفة ما إذا كان الرقم "NaN" ، يمكنك استخدام math.isnan() كـ:

>>> import math
>>> nan_num = float('nan')

>>> math.isnan(nan_num)
True

أو إذا كنت لا ترغب في استيراد مكتبة إضافية للتحقق من ذلك ، يمكنك ببساطة التحقق من ذلك من خلال مقارنةها مع نفسها باستخدام == . ترجع Python False عندما تتم مقارنة nan float بنفسها. فمثلا:

# `nan_num` variable is taken from above example
>>> nan_num == nan_num
False

وبالتالي ، يمكن تحديث الوظيفة أعلاه is_number لإرجاع False لـ "NaN" كـ:

def is_number(n):
    is_number = True
    try:
        num = float(n)
        # check for "nan" floats
        is_number = num == num   # or use `math.isnan(num)`
    except ValueError:
        is_number = False
    return is_number

نموذج تشغيل:

>>> is_number('Nan')   # not a number "Nan" string
False

>>> is_number('nan')   # not a number string "nan" with all lower cased
False

>>> is_number('123')   # positive integer
True

>>> is_number('-123')  # negative integer
True

>>> is_number('-1.12') # negative `float`
True

>>> is_number('abc')   # "some random" string
False

PS: Each operation for each check depending on the type of number comes with additional overhead. Choose the version of is_number function which fits your requirement.



To check if the input value is a float , you can compare the type of the input to a float

def isFloat(s):
    realFloat = 0.1

    if type(s) == type(realFloat):
        return True
    else:
        return False

عائدات:

False     # s = 5
True      # s = 1.2345

فإن آخر الأصلي يعود في الواقع Trueل s = 5أنه هو رقم (صحيح) ويمكنك يلقي intإلى floatدون ValueError. إذا كنت تحاول التحقق من أنها فعلية floatبدلاً من مجرد رقم ، فستحتاج إلى حساب هذه الحالة.


بالنسبة إلى سلاسل غير أرقام ، try: except: أبطأ من التعبيرات العادية. بالنسبة لسلاسل الأرقام الصالحة ، يكون التعبير العادي أبطأ. لذلك ، تعتمد الطريقة المناسبة على المدخلات الخاصة بك.

إذا وجدت أنك في أحد fastnumbers الأداء ، فيمكنك استخدام وحدة نمطية جديدة تابعة لجهة خارجية تسمى fastnumbers توفر وظيفة تسمى isfloat . الكشف الكامل ، أنا المؤلف. لقد أدرجت نتائجها في التوقيت أدناه.

from __future__ import print_function
import timeit

prep_base = '''\
x = 'invalid'
y = '5402'
z = '4.754e3'
'''

prep_try_method = '''\
def is_number_try(val):
    try:
        float(val)
        return True
    except ValueError:
        return False

'''

prep_re_method = '''\
import re
float_match = re.compile(r'[-+]?\d*\.?\d+(?:[eE][-+]?\d+)?$').match
def is_number_re(val):
    return bool(float_match(val))

'''

fn_method = '''\
from fastnumbers import isfloat

'''

print('Try with non-number strings', timeit.timeit('is_number_try(x)',
    prep_base + prep_try_method), 'seconds')
print('Try with integer strings', timeit.timeit('is_number_try(y)',
    prep_base + prep_try_method), 'seconds')
print('Try with float strings', timeit.timeit('is_number_try(z)',
    prep_base + prep_try_method), 'seconds')
print()
print('Regex with non-number strings', timeit.timeit('is_number_re(x)',
    prep_base + prep_re_method), 'seconds')
print('Regex with integer strings', timeit.timeit('is_number_re(y)',
    prep_base + prep_re_method), 'seconds')
print('Regex with float strings', timeit.timeit('is_number_re(z)',
    prep_base + prep_re_method), 'seconds')
print()
print('fastnumbers with non-number strings', timeit.timeit('isfloat(x)',
    prep_base + 'from fastnumbers import isfloat'), 'seconds')
print('fastnumbers with integer strings', timeit.timeit('isfloat(y)',
    prep_base + 'from fastnumbers import isfloat'), 'seconds')
print('fastnumbers with float strings', timeit.timeit('isfloat(z)',
    prep_base + 'from fastnumbers import isfloat'), 'seconds')
print()
Try with non-number strings 2.39108395576 seconds
Try with integer strings 0.375686168671 seconds
Try with float strings 0.369210958481 seconds

Regex with non-number strings 0.748660802841 seconds
Regex with integer strings 1.02021503448 seconds
Regex with float strings 1.08564686775 seconds

fastnumbers with non-number strings 0.174362897873 seconds
fastnumbers with integer strings 0.179651021957 seconds
fastnumbers with float strings 0.20222902298 seconds

كما ترى

  • try: except: كانت سريعة لإدخال رقمي ولكنها بطيئة جدًا لإدخال غير صحيح
  • يكون regex فعالاً للغاية عندما يكون الإدخال غير صالح
  • يفوز fastnumbers في كلتا الحالتين

You may use regex.

number = raw_input("Enter a number: ")
if re.match(r'^\d+$', number):
    print "It's integer"
    print int(number)
elif re.match(r'^\d+\.\d+$', number):
    print "It's float"
    print float(number)
else:
    print("Please enter a number")

هناك استثناء واحد قد ترغب في أخذه بعين الاعتبار: السلسلة "NaN"

إذا كنت تريد أن يقوم is_number بإرجاع FALSE لـ "NaN" ، فلن يعمل هذا الرمز لأن Python تقوم بتحويله إلى تمثيل له لرقم ليس رقمًا (الحديث عن مشكلات الهوية):

>>> float('NaN')
nan

بخلاف ذلك ، ينبغي أن أشكرك بالفعل على جزء الشفرة الذي أستخدمه الآن على نطاق واسع. :)

G.


لذا لوضع كل ذلك معا ، والتحقق من نان ، اللانهاية والأرقام المعقدة (يبدو أنها محددة مع ي ، وليس أنا ، أي 1 + 2J) فإنه يؤدي إلى:

def is_number(s):
    try:
        n=str(float(s))
        if n == "nan" or n=="inf" or n=="-inf" : return False
    except ValueError:
        try:
            complex(s) # for complex
        except ValueError:
            return False
    return True

وماذا عن هذا:

'3.14'.replace('.','',1).isdigit()

التي ستعود فقط إذا كان هناك واحد أو لا. في سلسلة من الأرقام.

'3.14.5'.replace('.','',1).isdigit()

سيعود كاذبة

تعديل: شاهد تعليقًا آخر ... يمكن إضافة .replace(badstuff,'',maxnum_badstuff) لحالات أخرى. إذا كنت تمر الملح وليس التوابل التعسفية (المرجع: xkcd#974 ) هذا سوف نفعل ما يرام: P.


من المحتمل أن يكون وضع تعويم واصطياد القيمة ValueError أسرع طريقة ، حيث أن float () مخصص لهذا الغرض على وجه التحديد. أي شيء آخر يتطلب تحليل سلسلة (regex ، الخ) من المرجح أن يكون أبطأ بسبب حقيقة أنه لم يتم ضبطه لهذه العملية. بلدي 0.02 دولار.


الذي ، ليس فقط بشع وبطيء ، يبدو عالي الكعب.

قد يستغرق الأمر بعض التعود ، ولكن هذه هي الطريقة المثالية للقيام بذلك. وكما أشير بالفعل ، فإن البدائل أسوأ. ولكن هناك ميزة واحدة أخرى للقيام بهذه الأمور بهذه الطريقة: تعدد الأشكال.

الفكرة الأساسية وراء كتابة البط هي أنه "إذا كان يمشي ويتحدث وكأنه بطة ، فذلك هو البط". ماذا لو قررت أنك بحاجة إلى سلسلة فئة فرعية بحيث يمكنك تغيير كيفية تحديد ما إذا كان يمكن تحويل شيء ما إلى عوامة؟ أو ماذا إذا قررت اختبار بعض الأشياء الأخرى بالكامل؟ يمكنك القيام بهذه الأشياء دون الحاجة إلى تغيير الرمز أعلاه.

اللغات الأخرى حل هذه المشاكل باستخدام واجهات. سأحفظ تحليل الحل الذي هو أفضل لمؤشر آخر. على الرغم من ذلك ، فإن النقطة هي أن الثعبان هو بالتأكيد على الجانب المكتوب من المعادلة ، وعليك أن تعتاد على بناء الجملة على هذا النحو إذا كنت تخطط للقيام بالكثير من البرمجة في بايثون (لكن هذا لا يعني عليك أن تحب ذلك بالطبع).

هناك أمر آخر قد ترغب في أخذه بعين الاعتبار: بيثون سريعة في إلقاء الاستثناءات والتقاطها مقارنة بالكثير من اللغات الأخرى (أسرع 30 مرة من .Net على سبيل المثال). هيك ، اللغة نفسها حتى يلقي استثناءات لتوصيل شروط البرنامج غير استثنائية ، العادي (في كل مرة تستخدم فيها حلقة for). وبالتالي ، لا داعي للقلق كثيرا بشأن جوانب الأداء لهذا القانون حتى تلاحظ مشكلة كبيرة.


You can generalize the exception technique in a useful way by returning more useful values than True and False. For example this function puts quotes round strings but leaves numbers alone. Which is just what I needed for a quick and dirty filter to make some variable definitions for R.

import sys

def fix_quotes(s):
    try:
        float(s)
        return s
    except ValueError:
        return '"{0}"'.format(s)

for line in sys.stdin:
    input = line.split()
    print input[0], '<- c(', ','.join(fix_quotes(c) for c in input[1:]), ')'

Try this.

 def is_number(var):
    try:
       if var == int(var):
            return True
    except Exception:
        return False

I also used the function you mentioned, but soon I notice that strings as "Nan", "Inf" and it's variation are considered as number. So I propose you improved version of your function, that will return false on those type of input and will not fail "1e3" variants:

def is_float(text):
    try:
        float(text)
        # check for nan/infinity etc.
        if text.isalpha():
            return False
        return True
    except ValueError:
        return False

تم تحديثه بعد أن أشار Alfe إلى أنك لست بحاجة إلى التحقق من وجود عوامة على نحو منفصل نظرًا لأن المقابض المعقدة تشتمل على:

def is_number(s):
    try:
        complex(s) # for int, long, float and complex
    except ValueError:
        return False

    return True

قيل سابقا: هل من بعض الحالات النادرة قد تحتاج أيضا إلى التحقق من الأعداد المركبة (مثل 1 + 2i) ، والتي لا يمكن تمثيلها بعائمة:

def is_number(s):
    try:
        float(s) # for int, long and float
    except ValueError:
        try:
            complex(s) # for complex
        except ValueError:
            return False

    return True

يقترح ريان

إذا كنت تريد إرجاع False لـ NaN و Inf ، غيّر السطر إلى x = float (s)؛ return (x == x) و (x - 1! = x). هذا يجب إرجاع True لكافة العوامات باستثناء Inf و NaN

ولكن هذا لا ينجح تمامًا ، نظرًا لأن x-1 == x يعود بشكل صحيح إلى عوامات كبيرة بما فيه الكفاية. على سبيل المثال ، 2.0**54 - 1 == 2.0**54


في حالة البحث عن أعداد صحيحة (موجبة وغير موقعة) بدلاً من floats ، يمكنك استخدام الدالة isdigit() لكائنات السلسلة.

>>> a = "03523"
>>> a.isdigit()
True
>>> b = "963spam"
>>> b.isdigit()
False

طرق سلسلة - isdigit()

هناك أيضا شيء على سلاسل Unicode ، وأنا لست على دراية Unicode - هو عشري / عشري


تستخدم بعد ذلك يعالج جميع الحالات: -

import re
a=re.match('((\d+[\.]\d*$)|(\.)\d+$)' ,  '2.3') 
a=re.match('((\d+[\.]\d*$)|(\.)\d+$)' ,  '2.')
a=re.match('((\d+[\.]\d*$)|(\.)\d+$)' ,  '.3')
a=re.match('((\d+[\.]\d*$)|(\.)\d+$)' ,  '2.3sd')
a=re.match('((\d+[\.]\d*$)|(\.)\d+$)' ,  '2.3')

If you want to know if the entire string can be represented as a number you'll want to use a regexp (or maybe convert the float back to a string and compare it to the source string, but I'm guessing that's not very fast).


Here's my simple way of doing it. Let's say that I'm looping through some strings and I want to add them to an array if they turn out to be numbers.

try:
    myvar.append( float(string_to_check) )
except:
    continue

Replace the myvar.apppend with whatever operation you want to do with the string if it turns out to be a number. The idea is to try to use a float() operation and use the returned error to determine whether or not the string is a number.


التي ، ليس فقط قبيحة وبطيئة

سأناقش كلاهما

سيكون التعابير المعتادة أو تحليل السلسلة الأخرى أقبح وأبطأ.

لست متأكدا من أن أي شيء يمكن أن يكون أسرع بكثير مما سبق. انها تدعو وظيفة والعودة. لا تقدم أداة Try / Catch الكثير من الحمل لأن الاستثناء الأكثر شيوعًا يتم اكتشافه بدون إجراء بحث شامل عن إطارات المكدس.

المشكلة هي أن أي دالة تحويل رقمية لها نوعان من النتائج

  • رقم ، إذا كان الرقم صالحًا
  • رمز الحالة (على سبيل المثال ، عبر errno) أو الاستثناء لإظهار أنه لا يمكن تحليل رقم صالح.

C (على سبيل المثال) الاختراق حول هذا عدد من الطرق. بيثون تضعها بوضوح وصراحة.

أعتقد أن الشفرة الخاصة بك للقيام بذلك مثالية.


على سبيل المثال ، إليك طريقتان:

Integer x = Integer.valueOf(str);
// or
int y = Integer.parseInt(str);

يوجد اختلاف بسيط بين هذه الطرق:

  • إرجاع valueOf مثيل جديد أو تخزين مؤقت من java.lang.Integer
  • parseInt يعود int .

وينطبق الشيء نفسه على جميع الحالات: Short.valueOf / parseShort ، Long.valueOf / parseLong ، إلخ.





python casting floating-point type-conversion