ฉันจะตรวจสอบว่าสตริงเป็นตัวเลข (ลอย) ได้อย่างไร?


1607

วิธีที่ดีที่สุดในการตรวจสอบว่าสตริงสามารถแสดงเป็นตัวเลขใน Python ได้อย่างไร

ฟังก์ชั่นที่ฉันมีอยู่ในขณะนี้คือ:

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

ซึ่งไม่เพียง แต่น่าเกลียดและช้าเท่านั้น อย่างไรก็ตามฉันไม่พบวิธีที่ดีกว่าเพราะการโทรfloatในฟังก์ชั่นหลักนั้นแย่กว่าเดิม


61
เกิดอะไรขึ้นกับโซลูชันปัจจุบันของคุณคืออะไร มันสั้นเร็วและอ่านง่าย
พันเอก Panic

5
และคุณไม่จำเป็นต้องส่งคืนจริงหรือเท็จ คุณสามารถคืนค่าที่แก้ไขอย่างเหมาะสมแทน - ตัวอย่างเช่นคุณสามารถใช้สิ่งนี้เพื่อใส่ไม่ใช่ตัวเลขในเครื่องหมายคำพูด
Thruston

7
จะดีกว่าไหมที่จะส่งคืนผลลัพธ์ของการลอยในกรณีที่การแปลงสำเร็จ คุณยังคงมีการตรวจสอบเพื่อความสำเร็จ (ผลลัพธ์เป็นเท็จ) และคุณมีการแปลงที่คุณต้องการแล้ว
Jiminion

8
แม้ว่าคำถามนี้เป็นรุ่นเก่า, ฉันแค่อยากจะบอกว่านี่เป็นวิธีที่สง่างามซึ่งเป็นเอกสารที่เป็นEAFP ดังนั้นอาจเป็นทางออกที่ดีที่สุดสำหรับปัญหาประเภทนี้
thiruvenkadam

7
อย่าส่งคืนผลลัพธ์ของการลอยหรือไม่มีเมื่อล้มเหลว ถ้าคุณใช้มันเพราะx = float('0.00'); if x: use_float(x);คุณมีข้อผิดพลาดในรหัสของคุณ ค่าความจริงคือเหตุผลที่ฟังก์ชั่นเหล่านี้ยกข้อยกเว้นแทนที่จะกลับมาNoneในครั้งแรก ทางออกที่ดีกว่าคือการหลีกเลี่ยงฟังก์ชั่นยูทิลิตี้และล้อมการโทรให้ลอยในtry catchเมื่อคุณต้องการใช้
ovangle

คำตอบ:


698

ซึ่งไม่เพียง แต่น่าเกลียดและช้า

ฉันจะโต้แย้งทั้งสอง

regex หรือวิธีการแยกสตริงอื่น ๆ จะน่าเกลียดและช้าลง

ฉันไม่แน่ใจว่าจะมีอะไรเร็วไปกว่านี้อีกแล้ว มันเรียกฟังก์ชั่นและผลตอบแทน ลอง / จับไม่แนะนำค่าใช้จ่ายมากเพราะข้อยกเว้นที่พบบ่อยที่สุดคือการจับโดยไม่ต้องค้นหาเฟรมสแต็ก

ปัญหาคือฟังก์ชันการแปลงตัวเลขใด ๆ มีผลลัพธ์สองประเภท

  • ตัวเลขถ้าตัวเลขถูกต้อง
  • รหัสสถานะ (เช่นผ่าน errno) หรือข้อยกเว้นเพื่อแสดงว่าไม่มีการแยกวิเคราะห์หมายเลขที่ถูกต้อง

C (เป็นตัวอย่าง) แฮ็กหลายวิธีนี้ Python วางไว้อย่างชัดเจนและชัดเจน

ฉันคิดว่ารหัสของคุณสำหรับการทำเช่นนี้สมบูรณ์แบบ


21
ฉันไม่คิดว่ารหัสที่สมบูรณ์แบบ ( แต่ฉันคิดว่ามันใกล้มาก): มันเป็นปกติที่จะนำเฉพาะส่วนที่ถูก "ทดสอบ" ในtryประโยคดังนั้นฉันจะใส่return Trueในประโยคของelse tryหนึ่งในเหตุผลคือด้วยรหัสในคำถามถ้าฉันต้องตรวจสอบฉันจะต้องตรวจสอบว่าคำสั่งที่สองในtryข้อไม่สามารถเพิ่ม ValueError: ได้รับนี้ไม่ต้องใช้เวลามากหรือพลังสมอง แต่ทำไมต้องใช้เมื่อไม่มีความจำเป็น?
Eric O Lebigot

4
คำตอบนั้นดูน่าสนใจ แต่ทำให้ฉันสงสัยว่าทำไมมันไม่มีให้เลย ... ฉันจะคัดลอกและใช้มันในทุกกรณี
ปราชญ์

9
ช่างน่ากลัวจริงๆ ถ้าฉันไม่สนใจว่าตัวเลขเป็นเท่าไหร่(ซึ่งเป็นสิ่งที่ทำให้ฉันมาที่นี่) แทนที่จะเป็น 1 บรรทัดIsNumeric()ฉันจะจบลงด้วยการลอง / การจับหรือการพันด้วยการลอง / การจับอีกครั้ง Ugh
พื้นฐาน

6
มันไม่ได้ให้ 'ออกจากกล่อง' เพราะเป็นหมายเลขเดียวกันของสายรหัสเป็นif is_number(s): x = float(x) else: // fail try: x = float(x) catch TypeError: # failฟังก์ชั่นยูทิลิตี้นี้เป็นนามธรรมที่ไม่จำเป็นทั้งหมด
ovangle

12
แต่สิ่งที่เป็นนามธรรมเป็นจุดรวมของห้องสมุด การมีฟังก์ชั่น 'isNumber' (ในภาษาใด ๆ ) จะช่วยได้มากเพราะคุณสามารถสร้างมันได้โดยตรงหากข้อความสั่งและมีโค้ดที่อ่านง่ายและสามารถบำรุงรักษาได้มากขึ้นโดยอาศัยบล็อกแบบลองจับ นอกจากนี้หากคุณต้องการใช้รหัสมากกว่าหนึ่งครั้งในมากกว่าหนึ่งคลาส / โมดูลคุณจะต้องใช้รหัสบรรทัดมากกว่าฟังก์ชั่นในตัว
JamEngulfer

1612

ในกรณีที่คุณกำลังมองหาการแยกจำนวนเต็ม (บวก, ไม่ได้ลงนาม) แทนการลอยคุณสามารถใช้isdigit()ฟังก์ชั่นสำหรับวัตถุสตริง

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

วิธีการสตริง - isdigit(): Python2 , Python3

มีบางอย่างในสตริง Unicode ซึ่งฉันไม่คุ้นเคยกับ Unicode - เป็นทศนิยม / ทศนิยม


232
นั่นเป็นผลลบต่อเนกาทีฟเช่นกัน
กล้าหาญ

22
ล้มเหลวด้วยการชี้แจงเช่นกัน: '1e3'.isdigit () -> False
ssc

35
ในขณะที่ Number! = Digit ผู้ที่กำลังมองหาวิธีทดสอบว่าสตริงมีจำนวนเต็มอาจสะดุดกับคำถามนี้เป็นอย่างดีและวิธีการ isDigit อาจเหมาะอย่างยิ่งสำหรับการใช้งานของพวกเขา
Adam Parkin

8
@ AdamParkin: isdigit()และint()มีความคิดเห็นที่แตกต่างกันเกี่ยวกับสิ่งที่เป็นจำนวนเต็มเช่นสำหรับตัวอักษร Unicode u'\u00b9': u'¹'.isdigit()เป็นTrueแต่int(u'¹')เพิ่ม ValueError
jfs

6
+1: isdigit () อาจไม่ใช่สิ่งที่ OP กำลังมองหา แต่เป็นสิ่งที่ฉันต้องการ อาจไม่ใช่กรณีที่คำตอบและวิธีการนี้ไม่ครอบคลุมตัวเลขทุกประเภท แต่ก็ยังมีความเกี่ยวข้องสูงซึ่งตรงกันข้ามกับข้อโต้แย้งเกี่ยวกับความถูกต้องของมัน ในขณะที่ "Number! = Digit" หลักยังคงเป็นชุดย่อยของตัวเลขโดยเฉพาะอย่างยิ่งตัวเลขที่เป็นค่าบวกไม่เป็นลบและใช้ฐาน 1-10 นอกจากนี้วิธีนี้มีประโยชน์อย่างยิ่งและสั้น ๆ สำหรับกรณีที่คุณต้องการตรวจสอบว่าสตริงเป็น ID ตัวเลขหรือไม่ซึ่งมักจะอยู่ในชุดย่อยของตัวเลขที่ฉันเพิ่งอธิบาย
Justin Johnson

161

TL; DRทางออกที่ดีที่สุดคือs.replace('.','',1).isdigit()

ฉันได้ทำการเปรียบเทียบเปรียบเทียบวิธีการที่แตกต่างกัน

def is_number_tryexcept(s):
    """ Returns True is string is a number. """
    try:
        float(s)
        return True
    except ValueError:
        return False

import re    
def is_number_regex(s):
    """ Returns True is string is a number. """
    if re.match("^\d+?\.\d+?$", s) is None:
        return s.isdigit()
    return True


def is_number_repl_isdigit(s):
    """ Returns True is string is a number. """
    return s.replace('.','',1).isdigit()

หากสตริงไม่ใช่ตัวเลขบล็อกยกเว้นจะค่อนข้างช้า แต่ที่สำคัญกว่านั้นลองดูข้อยกเว้นเป็นวิธีการเดียวที่จัดการกับสัญลักษณ์ทางวิทยาศาสตร์ได้อย่างถูกต้อง

funcs = [
          is_number_tryexcept, 
          is_number_regex,
          is_number_repl_isdigit
          ]

a_float = '.1234'

print('Float notation ".1234" is not supported by:')
for f in funcs:
    if not f(a_float):
        print('\t -', f.__name__)

เครื่องหมายลอย ".1234" ไม่ได้รับการสนับสนุนโดย:
- is_number_regex

scientific1 = '1.000000e+50'
scientific2 = '1e50'


print('Scientific notation "1.000000e+50" is not supported by:')
for f in funcs:
    if not f(scientific1):
        print('\t -', f.__name__)




print('Scientific notation "1e50" is not supported by:')
for f in funcs:
    if not f(scientific2):
        print('\t -', f.__name__)

วิทยาศาสตร์สัญกรณ์ "1.000000e + 50" ไม่ได้รับการสนับสนุนโดย:
- is_number_regex
- is_number_repl_isdigit
สัญกรณ์วิทยาศาสตร์ "1e50" ไม่ได้รับการสนับสนุนโดย:
- is_number_regex
- is_number_repl_isdigit

แก้ไข: ผลลัพธ์มาตรฐาน

import timeit

test_cases = ['1.12345', '1.12.345', 'abc12345', '12345']
times_n = {f.__name__:[] for f in funcs}

for t in test_cases:
    for f in funcs:
        f = f.__name__
        times_n[f].append(min(timeit.Timer('%s(t)' %f, 
                      'from __main__ import %s, t' %f)
                              .repeat(repeat=3, number=1000000)))

ที่ทดสอบฟังก์ชั่นต่อไปนี้

from re import match as re_match
from re import compile as re_compile

def is_number_tryexcept(s):
    """ Returns True is string is a number. """
    try:
        float(s)
        return True
    except ValueError:
        return False

def is_number_regex(s):
    """ Returns True is string is a number. """
    if re_match("^\d+?\.\d+?$", s) is None:
        return s.isdigit()
    return True


comp = re_compile("^\d+?\.\d+?$")    

def compiled_regex(s):
    """ Returns True is string is a number. """
    if comp.match(s) is None:
        return s.isdigit()
    return True


def is_number_repl_isdigit(s):
    """ Returns True is string is a number. """
    return s.replace('.','',1).isdigit()

ป้อนคำอธิบายรูปภาพที่นี่


15
สำหรับชาร์ตที่ดี +1 ฉันเห็นมาตรฐานและเห็นกราฟ TL ทั้งหมดสิ่ง DR กลายเป็นชัดเจนและใช้งานง่าย
jcchuks

ฉันเห็นด้วยกับ @JCChuks: กราฟช่วยได้มากในการรับ TL; DR ได้อย่างรวดเร็ว แต่ฉันคิดว่า TL; DR (เช่น: TL; DR : ทางออกที่ดีที่สุดคือ s.replace('.','',1).isdigit()) ควรปรากฏที่จุดเริ่มต้นของโปรแกรมตรวจสอบนี้ ไม่ว่าในกรณีใดควรเป็นที่ยอมรับ ขอบคุณ!
Simon C.

10
วิธีนี้ไม่ได้จัดการกับจำนวนลบ (ขีดกลาง) ฉันอยากจะแนะนำให้ใช้วิธีการลอยเนื่องจากมีแนวโน้มที่จะเกิดข้อผิดพลาดน้อยลงและจะทำงานทุกครั้ง
Urchin

3
สิ่งสำคัญที่ควรทราบคือแม้ในกรณีที่ไม่มีเส้นประ แต่วิธี replace-isdigit นั้นเร็วกว่าสำหรับผู้ที่ไม่ใช่ตัวเลขเท่านั้น หากอินพุตส่วนใหญ่ของคุณเป็นอินพุตที่ถูกต้องคุณก็ยังดีกว่าด้วยโซลูชันลองข้อยกเว้น!
Markus von Broady

1
ใช้งานไม่ได้กับรูปแบบเลขชี้กำลังแบบ exponential เช่น'1.5e-9'หรือเชิงลบ
EL_DON

68

มีข้อยกเว้นหนึ่งข้อที่คุณอาจต้องคำนึงถึงคือสตริง 'NaN'

หากคุณต้องการให้ is_number ส่งคืน FALSE สำหรับ 'NaN' รหัสนี้จะไม่ทำงานเนื่องจาก Python แปลงเป็นรหัสที่ไม่ใช่ตัวเลข (พูดถึงปัญหาเอกลักษณ์):

>>> float('NaN')
nan

มิฉะนั้นฉันควรจะขอบคุณจริงๆสำหรับชิ้นส่วนของรหัสที่ฉันใช้ตอนนี้อย่างกว้างขวาง :)

กรัม


2
ที่จริงแล้วNaNอาจเป็นค่าที่ดีในการส่งคืน (แทนFalse) หากข้อความที่ส่งผ่านไม่ได้เป็นตัวแทนของตัวเลข การตรวจสอบว่าเป็นความเจ็บปวดหรือไม่ ( floatชนิดของ Python ต้องการวิธีการจริงๆ) แต่คุณสามารถใช้ในการคำนวณได้โดยไม่เกิดข้อผิดพลาดและต้องตรวจสอบผลลัพธ์เท่านั้น
kindall

7
'inf'ยกเว้นก็คือสตริง อย่างใดอย่างหนึ่งinfหรือNaNนอกจากนี้ยังสามารถนำหน้าด้วย+หรือ-และยังคงได้รับการยอมรับ
agf

4
หากคุณต้องการคืนค่าเท็จสำหรับ NaN และ Inf ให้เปลี่ยนบรรทัดเป็น x = float return (x == x) และ (x - 1! = x) สิ่งนี้จะส่งกลับค่า True สำหรับการลอยทั้งหมดยกเว้น Inf และ NaN
RyanN

5
x-1 == xinfเป็นจริงสำหรับลอยขนาดใหญ่มีขนาดเล็กกว่า จาก Python 3.2 คุณสามารถใช้math.isfiniteเพื่อทดสอบตัวเลขที่ไม่ใช่ NaN หรือไม่สิ้นสุดหรือตรวจสอบทั้งคู่math.isnanและmath.isinfก่อนหน้านั้น
Steve Jessop

56

เกี่ยวกับสิ่งนี้:

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

ซึ่งจะคืนค่าจริงหากมีเพียงหนึ่งหรือไม่มี '.' ในสตริงของตัวเลข

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

จะกลับเท็จ

แก้ไข: เพิ่งเห็นความคิดเห็นอื่น ... การเพิ่ม.replace(badstuff,'',maxnum_badstuff)กรณีอื่นสามารถทำได้ หากคุณกำลังผ่านเกลือและไม่ใช่เครื่องปรุงรสตามอำเภอใจ (อ้างอิง: xkcd # 974 ) สิ่งนี้จะทำได้ดี: P


7
อย่างไรก็ตามสิ่งนี้ไม่ได้คิดเป็นจำนวนลบ
Michael Barton

5
หรือตัวเลขที่มีเลขชี้กำลังเช่น1.234e56(ซึ่งอาจถูกเขียนเป็น+1.234E+56และอีกหลายสายพันธุ์)
Alfe

re.match(r'^[+-]*(0[xbo])?[0-9A-Fa-f]*\.?[0-9A-Fa-f]*(E[+-]*[0-9A-Fa-f]+)$', 'str')ควรทำงานได้ดีขึ้นในการกำหนดตัวเลข (แต่ไม่ใช่ทั้งหมดฉันไม่ได้อ้างสิทธิ์นั้น) ฉันไม่แนะนำให้ใช้สิ่งนี้ดีกว่าการใช้รหัสดั้งเดิมของผู้ถาม
Baldrickk

ถ้าคุณไม่ชอบวิธีนี้อ่านก่อนลง downvoting!
aloisdg กำลังย้ายไปยัง codidact.com

ผู้ชายนี่เป็นทางออกที่ฉลาดที่สุดที่ฉันเคยเห็นในเว็บไซต์นี้!
Karam Qusai

41

ซึ่งไม่เพียง แต่น่าเกลียดและช้าเท่านั้น

อาจใช้เวลาทำความคุ้นเคย แต่นี่เป็นวิธีการทำอย่างไพเราะ ดังที่ได้กล่าวไว้แล้วว่าทางเลือกนั้นแย่กว่า แต่มีข้อได้เปรียบอีกข้อหนึ่งในการทำสิ่งนี้: polymorphism

แนวคิดหลักที่อยู่เบื้องหลังการพิมพ์เป็ดคือ "ถ้ามันเดินและพูดเหมือนเป็ดแล้วมันก็เป็นเป็ด" ถ้าคุณตัดสินใจว่าคุณต้องการ subclass string เพื่อให้คุณสามารถเปลี่ยนวิธีการพิจารณาว่ามีบางสิ่งที่สามารถแปลงเป็น float ได้หรือไม่? หรือถ้าคุณตัดสินใจที่จะทดสอบวัตถุอื่นอย่างสิ้นเชิง? คุณสามารถทำสิ่งเหล่านี้ได้โดยไม่ต้องเปลี่ยนโค้ดด้านบน

ภาษาอื่น ๆ แก้ปัญหาเหล่านี้โดยใช้ส่วนต่อประสาน ฉันจะบันทึกการวิเคราะห์โซลูชันที่ดีกว่าสำหรับเธรดอื่น อย่างไรก็ตามประเด็นก็คือว่าไพ ธ อนนั้นอยู่ด้านการพิมพ์เป็ดของสมการอย่างแน่นอนและคุณอาจต้องคุ้นเคยกับไวยากรณ์เช่นนี้หากคุณวางแผนที่จะเขียนโปรแกรมจำนวนมากใน Python (แต่นั่นไม่ได้หมายความว่า คุณต้องชอบแน่นอน)

อีกสิ่งหนึ่งที่คุณอาจต้องคำนึงถึง: Python ค่อนข้างเร็วในการขว้างและจับข้อยกเว้นเมื่อเทียบกับภาษาอื่น ๆ จำนวนมาก (เร็วกว่า 30 เท่าเช่น. Net) Heck ภาษาเองก็มีข้อยกเว้นในการสื่อสารเงื่อนไขโปรแกรมปกติที่ไม่พิเศษ (ทุกครั้งที่คุณใช้สำหรับลูป) ดังนั้นฉันจะไม่กังวลมากเกินไปเกี่ยวกับประสิทธิภาพของรหัสนี้จนกว่าคุณจะสังเกตเห็นปัญหาที่สำคัญ


1
อีกหนึ่งสถานที่ทั่วไปที่หลามใช้ข้อยกเว้นสำหรับฟังก์ชั่นพื้นฐานในhasattr()ซึ่งเป็นเพียงการโทรในห่อgetattr() try/exceptถึงกระนั้นการจัดการข้อยกเว้นจะช้ากว่าการควบคุมการไหลปกติดังนั้นการใช้มันสำหรับบางสิ่งที่จะเป็นจริงส่วนใหญ่อาจส่งผลให้เกิดการปรับประสิทธิภาพ
kindall

ดูเหมือนว่าหากคุณต้องการสายการบินเดียวคุณเป็น SOL
พื้นฐาน

นอกจากนี้ไพทอนยังเป็นแนวคิดที่ว่า "ควรขอการให้อภัยมากกว่าการอนุญาต" ซึ่งเกี่ยวข้องกับผลกระทบของการมีข้อยกเว้นราคาถูก
heltonbiker

40

อัปเดตหลังจาก 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

14
ฉันไม่เห็นด้วย. นั่นเป็นเรื่องที่ไม่ค่อยเกิดขึ้นในการใช้งานปกติและคุณควรสร้าง is_complex_number () โทรหาคุณเมื่อคุณใช้พวกเขาแทนที่จะเป็นภาระการโทรที่มีการดำเนินการเพิ่มเติมสำหรับโอกาส 0.0001% ของการทำงานผิดพลาด
Jiminion

3
คุณสามารถดึงfloat()สิ่งต่าง ๆ ออกมาได้อย่างสมบูรณ์และเพียงแค่ตรวจสอบการcomplex()โทรให้สำเร็จ ทุกอย่างแยกวิเคราะห์โดยสามารถแยกวิเคราะห์โดยfloat() complex()
Alfe

ฟังก์ชันนี้จะคืนค่า NaNs และ Inf ของ Pandas เป็นค่าตัวเลข
fixxxer

complex('(01989)')(1989+0j)จะกลับมา แต่float('(01989)')จะล้มเหลว ดังนั้นฉันคิดว่าการใช้complexไม่ใช่ความคิดที่ดี
plhn

26

สำหรับการ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

2
ไม่สามารถจัดการสิ่งต่าง ๆ ที่1.234e56คล้ายกันได้ นอกจากนี้ฉันสนใจที่คุณจะรู้ว่า99999999999999999999e99999999999999999999ไม่ใช่ตัวเลข พยายามแยกวิเคราะห์มันค้นพบอย่างรวดเร็ว
Alfe

สิ่งนี้จะทำงานได้เร็วกว่าโซลูชั่นที่ยอมรับ 30 ~ 30% ในรายการสตริง 50m และเร็วกว่า 150% ในรายการสตริง 5k 👏
Zev Averbach

15

แค่เลียนแบบ C #

ใน C # มีฟังก์ชันที่แตกต่างกันสองฟังก์ชันที่จัดการการวิเคราะห์ค่าสเกลาร์:

  • Float.Parse ()
  • Float.TryParse ()

float.parse ():

def parse(string):
    try:
        return float(string)
    except Exception:
        throw TypeError

หมายเหตุ: หากคุณกำลังสงสัยว่าทำไมผมเปลี่ยนข้อยกเว้น TypeError ที่นี่เป็นเอกสาร

float.try_parse ():

def try_parse(string, fail=None):
    try:
        return float(string)
    except Exception:
        return fail;

หมายเหตุ: คุณไม่ต้องการคืนค่าบูลีน 'เท็จ' เนื่องจากยังคงเป็นประเภทค่า ไม่ดีกว่าเพราะมันบ่งบอกถึงความล้มเหลว แน่นอนถ้าคุณต้องการสิ่งที่แตกต่างคุณสามารถเปลี่ยนพารามิเตอร์ล้มเหลวเป็นสิ่งที่คุณต้องการ

ในการขยายโฟลว์เพื่อรวม 'parse ()' และ 'try_parse ()' คุณจะต้องลิงคลาส 'float' เพื่อเพิ่มเมธอดเหล่านี้

หากคุณต้องการเคารพฟังก์ชั่นที่มีอยู่แล้วรหัสควรเป็นดังนี้:

def monkey_patch():
    if(!hasattr(float, 'parse')):
        float.parse = parse
    if(!hasattr(float, 'try_parse')):
        float.try_parse = try_parse

SideNote: โดยส่วนตัวแล้วผมชอบเรียกมันว่า Monkey Punching เพราะมันให้ความรู้สึกเหมือนว่าฉันใช้ภาษาในทางที่ผิดเมื่อฉันทำเช่นนี้ แต่ YMMV

การใช้งาน:

float.parse('giggity') // throws TypeException
float.parse('54.3') // returns the scalar value 54.3
float.tryParse('twank') // returns None
float.tryParse('32.2') // returns the scalar value 32.2

และ Sage Python ผู้ยิ่งใหญ่พูดกับ Holy See Sharpisus ว่า "อะไรก็ตามที่เจ้าสามารถทำได้ฉันทำได้ดีกว่า; ฉันจะทำทุกอย่างได้ดีกว่าเธอ"


ฉันได้รับการเข้ารหัสในส่วนใหญ่ของ JS เมื่อเร็ว ๆ นี้และไม่ได้ทดสอบสิ่งนี้จริง ๆ ดังนั้นอาจมีข้อผิดพลาดเล็กน้อย หากคุณเห็นสิ่งใดรู้สึกอิสระที่จะแก้ไขข้อผิดพลาดของฉัน
Evan Plaice

หากต้องการเพิ่มการรองรับสำหรับจำนวนเชิงซ้อนดูคำตอบโดย @Matthew Wilcoxson stackoverflow.com/a/3335060/290340
Evan Plaice

1
การใช้!แทนที่จะnotเป็นข้อผิดพลาดเล็กน้อย แต่คุณไม่สามารถกำหนดแอตทริบิวต์ให้กับfloatCPython ในตัวได้
BlackJack

15

สำหรับสตริงที่ไม่ใช่ตัวเลขtry: except:จริง ๆ แล้วช้ากว่านิพจน์ทั่วไป สำหรับสตริงของตัวเลขที่ถูกต้อง regex จะช้าลง ดังนั้นวิธีการที่เหมาะสมขึ้นอยู่กับการป้อนข้อมูลของคุณ

หากคุณพบว่าคุณอยู่ในการผูกประสิทธิภาพคุณสามารถใช้โมดูลของบุคคลที่สามใหม่ที่เรียกว่า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 ชนะทั้งสองกรณี

ฉันยืนแก้ไข: -} มันดูเหมือนไม่ได้ทำแบบนี้ อาจใช้ชื่อที่ชอบprep_code_basisและprep_code_re_methodอาจป้องกันความผิดพลาดของฉัน
Alfe

คุณสนใจที่จะอธิบายวิธีการทำงานของโมดูลของคุณอย่างน้อยสำหรับisfloatฟังก์ชั่นนี้หรือไม่?
โซโลมอน Ucko

@SolomonUcko นี่คือลิงค์ไปยังซอร์สโค้ดสำหรับส่วนตรวจสอบสตริง: github.com/SethMMorton/fastnumbers/blob/v1.0.0/src/ … โดยพื้นฐานแล้วมันจะเดินข้ามอักขระแต่ละตัวในสตริงตามลำดับและตรวจสอบว่ามันเป็นไปตามรูปแบบสำหรับการลอยที่ถูกต้อง ถ้าใส่อยู่แล้วเป็นจำนวนมากก็แค่ใช้อย่างรวดเร็วPyFloat_Check
SethMMorton

1
ทดสอบกับทางเลือกที่ดีที่สุดในหัวข้อนี้ฉันขอยืนยันว่าการแก้ปัญหานี้คือไกลโดยเร็วที่สุด วิธีที่เร็วที่สุดที่สองคือstr(s).strip('-').replace('.','',1).isdigit()ซึ่งช้าลงประมาณ 10x!
Alexander McFarlane

14

ฉันรู้ว่ามันเก่าโดยเฉพาะ แต่ฉันจะเพิ่มคำตอบที่ฉันเชื่อว่าครอบคลุมข้อมูลที่หายไปจากคำตอบที่ได้รับการโหวตสูงสุดซึ่งอาจมีค่ามากสำหรับผู้ที่พบสิ่งนี้:

สำหรับแต่ละวิธีต่อไปนี้ให้เชื่อมต่อด้วยการนับหากคุณต้องการรับอินพุตใด ๆ (สมมติว่าเราใช้คำจำกัดความแกนนำของจำนวนเต็มมากกว่า 0-255 เป็นต้น)

x.isdigit() ทำงานได้ดีสำหรับการตรวจสอบว่า x เป็นจำนวนเต็ม

x.replace('-','').isdigit() ทำงานได้ดีสำหรับการตรวจสอบว่า x เป็นลบหรือไม่ (ตรวจสอบ - ในตำแหน่งแรก)

x.replace('.','').isdigit() ทำงานได้ดีสำหรับการตรวจสอบว่า x เป็นทศนิยมหรือไม่

x.replace(':','').isdigit() ทำงานได้ดีสำหรับการตรวจสอบว่า x เป็นอัตราส่วน

x.replace('/','',1).isdigit() ทำงานได้ดีสำหรับการตรวจสอบว่า x เป็นเศษส่วนหรือไม่


1
แม้ว่าจะเป็นเศษส่วนคุณอาจต้องทำx.replace('/','',1).isdigit()หรือวันอื่นเช่น 4/7/2560 อาจตีความผิดเป็นตัวเลข
Yuxuan เฉิน

สำหรับวิธีที่ดีที่สุดในการเชื่อมโยงเงื่อนไข: stackoverflow.com/q/3411771/5922329
Daniel Braun

13

คำตอบนี้ให้คำแนะนำทีละขั้นตอนมีฟังก์ชั่นพร้อมตัวอย่างเพื่อค้นหาสตริงคือ:

  • จำนวนเต็มบวก
  • บวก / ลบ - จำนวนเต็ม / ลอย
  • จะละทิ้งสตริง "NaN" (ไม่ใช่ตัวเลข) ขณะตรวจสอบหมายเลขได้อย่างไร

ตรวจสอบว่าสตริงเป็นจำนวนเต็มบวกหรือไม่

คุณอาจใช้str.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

หากคุณต้องการตรวจสอบจำนวนเต็มลบและfloatจากนั้นคุณอาจเขียนฟังก์ชันแบบกำหนดเองเพื่อตรวจสอบเป็น:

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: การดำเนินการแต่ละรายการสำหรับการตรวจสอบแต่ละครั้งขึ้นอยู่กับประเภทของหมายเลขที่มาพร้อมกับค่าใช้จ่ายเพิ่มเติม เลือกรุ่นของis_numberฟังก์ชั่นที่เหมาะกับความต้องการของคุณ


12

การส่งและรับ ValueError น่าจะเป็นวิธีที่เร็วที่สุดเนื่องจากการลอย () มีความหมายเฉพาะสำหรับสิ่งนั้น สิ่งอื่นใดที่ต้องมีการวิเคราะห์คำสตริง (regex ฯลฯ ) อาจจะช้าลงเนื่องจากข้อเท็จจริงที่ว่ามันไม่ได้ปรับสำหรับการดำเนินการนี้ ฉัน $ 0.02


11
ของคุณ "2e-2" ดอลลาร์ลอยเกินไป (อาร์กิวเมนต์เพิ่มเติมสำหรับการใช้ลอย :)
tzot

8
@tzot ไม่ใช้การลอยเพื่อแสดงค่าเงิน
ลุค

6
@ ลุค: ฉันเห็นด้วยกับคุณโดยสิ้นเชิงแม้ว่าฉันจะไม่เคยแนะนำให้ใช้การลอยเพื่อเป็นตัวแทนของค่าเงิน ผมแค่บอกว่าค่าเงินสามารถแสดงเป็นลอย :)
tzot

11

คุณสามารถใช้สตริง Unicode พวกเขามีวิธีการทำสิ่งที่คุณต้องการ:

>>> s = u"345"
>>> s.isnumeric()
True

หรือ:

>>> s = "345"
>>> u = unicode(s)
>>> u.isnumeric()
True

http://www.tutorialspoint.com/python/string_isnumeric.htm

http://docs.python.org/2/howto/unicode.html


2
สำหรับ ints ที่ไม่เป็นลบมันก็โอเค ;-)
andilabs

1
s.isdecimal()ตรวจสอบว่าsสตริงเป็นจำนวนเต็มไม่ใช่ค่าลบหรือไม่ s.isnumeric()รวมถึงตัวละครที่int()ปฏิเสธ
jfs

9

ฉันต้องการดูว่าวิธีใดเร็วที่สุด โดยรวมแล้วผลลัพธ์ที่ดีที่สุดและสอดคล้องกันมากที่สุดคือcheck_replaceฟังก์ชั่น check_exceptionฟังก์ชั่นที่ให้ผลเร็วที่สุดแต่ถ้าไม่มีข้อยกเว้นเท่านั้น - ความหมายของรหัสนั้นมีประสิทธิภาพมากที่สุด แต่ค่าใช้จ่ายในการขว้างข้อยกเว้นนั้นค่อนข้างมาก

โปรดทราบว่าการตรวจสอบนักแสดงที่ประสบความสำเร็จเป็นวิธีการเดียวที่มีความถูกต้องตัวอย่างเช่นวิธีนี้ใช้ได้กับcheck_exceptionแต่ฟังก์ชั่นการทดสอบอีกสองฟังก์ชั่นจะคืนค่า False สำหรับโฟลทที่ถูกต้อง:

huge_number = float('1e+100')

นี่คือรหัสมาตรฐาน:

import time, re, random, string

ITERATIONS = 10000000

class Timer:    
    def __enter__(self):
        self.start = time.clock()
        return self
    def __exit__(self, *args):
        self.end = time.clock()
        self.interval = self.end - self.start

def check_regexp(x):
    return re.compile("^\d*\.?\d*$").match(x) is not None

def check_replace(x):
    return x.replace('.','',1).isdigit()

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

to_check = [check_regexp, check_replace, check_exception]

print('preparing data...')
good_numbers = [
    str(random.random() / random.random()) 
    for x in range(ITERATIONS)]

bad_numbers = ['.' + x for x in good_numbers]

strings = [
    ''.join(random.choice(string.ascii_uppercase + string.digits) for _ in range(random.randint(1,10)))
    for x in range(ITERATIONS)]

print('running test...')
for func in to_check:
    with Timer() as t:
        for x in good_numbers:
            res = func(x)
    print('%s with good floats: %s' % (func.__name__, t.interval))
    with Timer() as t:
        for x in bad_numbers:
            res = func(x)
    print('%s with bad floats: %s' % (func.__name__, t.interval))
    with Timer() as t:
        for x in strings:
            res = func(x)
    print('%s with strings: %s' % (func.__name__, t.interval))

นี่คือผลลัพธ์ที่มี Python 2.7.10 ใน 2017 MacBook Pro 13:

check_regexp with good floats: 12.688639
check_regexp with bad floats: 11.624862
check_regexp with strings: 11.349414
check_replace with good floats: 4.419841
check_replace with bad floats: 4.294909
check_replace with strings: 4.086358
check_exception with good floats: 3.276668
check_exception with bad floats: 13.843092
check_exception with strings: 15.786169

นี่คือผลลัพธ์ที่มี Python 3.6.5 ใน 2017 MacBook Pro 13:

check_regexp with good floats: 13.472906000000009
check_regexp with bad floats: 12.977665000000016
check_regexp with strings: 12.417542999999995
check_replace with good floats: 6.011045999999993
check_replace with bad floats: 4.849356
check_replace with strings: 4.282754000000011
check_exception with good floats: 6.039081999999979
check_exception with bad floats: 9.322753000000006
check_exception with strings: 9.952595000000002

นี่คือผลลัพธ์ที่มี PyPy 2.7.13 ใน 2017 MacBook Pro 13:

check_regexp with good floats: 2.693217
check_regexp with bad floats: 2.744819
check_regexp with strings: 2.532414
check_replace with good floats: 0.604367
check_replace with bad floats: 0.538169
check_replace with strings: 0.598664
check_exception with good floats: 1.944103
check_exception with bad floats: 2.449182
check_exception with strings: 2.200056

10
คุณควรทดสอบประสิทธิภาพสำหรับกรณีที่ไม่ถูกต้อง ไม่มีข้อยกเว้นใด ๆ กับตัวเลขเหล่านี้ซึ่งเป็นส่วน "ช้า"
Ugo Méda

1
@ UgoMédaฉันรับคำแนะนำของคุณตั้งแต่ปี 2013 และทำได้ :)
Ron Reiter

"โปรดทราบว่าการตรวจสอบนักแสดงที่ประสบความสำเร็จเป็นวิธีเดียวที่แม่นยำ" <- นี่ไม่จริง ฉันใช้การทดสอบของคุณโดยใช้ regexp ในคำตอบของฉันข้างต้นและมันจะทำงานได้เร็วกว่า regexp ฉันจะเพิ่มผลลัพธ์ในคำตอบของฉันด้านบน
David Ljung Madison Stellar

อนึ่งในฐานะที่เป็นจุดน่าขบขันผู้สร้างตัวเลขที่ไม่ดีของคุณสามารถสร้างตัวเลขทางกฎหมายได้แม้ว่ามันจะค่อนข้างหายาก :)
David Ljung Madison Stellar

8

ดังนั้นเมื่อต้องการรวมมันเข้าด้วยกันการตรวจสอบหาตัวเลขน่านอินฟินิตี้และจำนวนเชิงซ้อน (ดูเหมือนว่าพวกมันจะถูกระบุด้วย j ไม่ใช่ i เช่น 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

จนถึงคำตอบที่ดีที่สุด ขอบคุณ
anish

6

อินพุตอาจเป็นดังนี้:

a="50" b=50 c=50.1 d="50.1"


อินพุต 1 ทั่วไป:

อินพุตของฟังก์ชั่นนี้สามารถเป็นได้ทุกอย่าง!

ค้นหาว่าตัวแปรที่กำหนดเป็นตัวเลขหรือไม่ สตริงตัวเลขประกอบด้วยเครื่องหมายทางเลือกจำนวนหลักใด ๆ ส่วนทศนิยมเสริมและส่วนเสริมไม่บังคับ ดังนั้น + 0123.45e6 จึงเป็นค่าตัวเลขที่ถูกต้อง ไม่อนุญาตให้ใช้เลขฐานสิบหก (เช่น 0xf4c3b00c) และไบนารี (เช่น 0b10100111001)

ฟังก์ชันis_numeric

import ast
import numbers              
def is_numeric(obj):
    if isinstance(obj, numbers.Number):
        return True
    elif isinstance(obj, str):
        nodes = list(ast.walk(ast.parse(obj)))[1:]
        if not isinstance(nodes[0], ast.Expr):
            return False
        if not isinstance(nodes[-1], ast.Num):
            return False
        nodes = nodes[1:-1]
        for i in range(len(nodes)):
            #if used + or - in digit :
            if i % 2 == 0:
                if not isinstance(nodes[i], ast.UnaryOp):
                    return False
            else:
                if not isinstance(nodes[i], (ast.USub, ast.UAdd)):
                    return False
        return True
    else:
        return False

ทดสอบ:

>>> is_numeric("54")
True
>>> is_numeric("54.545")
True
>>> is_numeric("0x45")
True

ฟังก์ชันis_float

พบว่าตัวแปรที่กำหนดเป็นลอย สตริงลอยประกอบด้วยเครื่องหมายตัวเลือกจำนวนหลักใด ๆ ...

import ast

def is_float(obj):
    if isinstance(obj, float):
        return True
    if isinstance(obj, int):
        return False
    elif isinstance(obj, str):
        nodes = list(ast.walk(ast.parse(obj)))[1:]
        if not isinstance(nodes[0], ast.Expr):
            return False
        if not isinstance(nodes[-1], ast.Num):
            return False
        if not isinstance(nodes[-1].n, float):
            return False
        nodes = nodes[1:-1]
        for i in range(len(nodes)):
            if i % 2 == 0:
                if not isinstance(nodes[i], ast.UnaryOp):
                    return False
            else:
                if not isinstance(nodes[i], (ast.USub, ast.UAdd)):
                    return False
        return True
    else:
        return False

ทดสอบ:

>>> is_float("5.4")
True
>>> is_float("5")
False
>>> is_float(5)
False
>>> is_float("5")
False
>>> is_float("+5.4")
True

astคืออะไร


2- ถ้าคุณมั่นใจว่าเนื้อหาตัวแปรเป็นString :

ใช้str.isdigit ()วิธีการ

>>> a=454
>>> a.isdigit()
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
AttributeError: 'int' object has no attribute 'isdigit'
>>> a="454"
>>> a.isdigit()
True

อินพุต 3 ตัวเลข:

ตรวจจับค่า int:

>>> isinstance("54", int)
False
>>> isinstance(54, int)
True
>>> 

ตรวจจับลอย:

>>> isinstance("45.1", float)
False
>>> isinstance(45.1, float)
True

" ast" คืออะไร

4

ฉันทำการทดสอบความเร็ว ให้บอกว่าถ้าสตริงมีแนวโน้มที่จะเป็นจำนวนลอง / ยกเว้นกลยุทธ์เป็นไปได้เร็วที่สุดถ้าสตริงไม่น่าจะเป็นตัวเลขและคุณมีความสนใจในการตรวจสอบจำนวนเต็มมันคุ้มค่าที่จะทำการทดสอบบางอย่าง (isdigit บวกหัวเรื่อง '-') หากคุณสนใจที่จะตรวจสอบหมายเลขลอยตัวคุณต้องใช้การลอง / ยกเว้นการโค้ด whitout


4

ฉันต้องการตรวจสอบว่าสตริงที่ส่งออกเป็นประเภทพื้นฐาน (float, int, str, bool) หลังจากไม่พบสิ่งใดบนอินเทอร์เน็ตฉันได้สร้างสิ่งนี้:

def str_to_type (s):
    """ Get possible cast type for a string

    Parameters
    ----------
    s : string

    Returns
    -------
    float,int,str,bool : type
        Depending on what it can be cast to

    """    
    try:                
        f = float(s)        
        if "." not in s:
            return int
        return float
    except ValueError:
        value = s.upper()
        if value == "TRUE" or value == "FALSE":
            return bool
        return type(s)

ตัวอย่าง

str_to_type("true") # bool
str_to_type("6.0") # float
str_to_type("6") # int
str_to_type("6abc") # str
str_to_type(u"6abc") # unicode       

คุณสามารถจับภาพประเภทและใช้งานได้

s = "6.0"
type_ = str_to_type(s) # float
f = type_(s) 

3

RyanN แนะนำ

ถ้าคุณต้องการคืนค่าเท็จสำหรับ NaN และ Inf ให้เปลี่ยนบรรทัดเป็น x = float (s); return (x == x) และ (x - 1! = x) สิ่งนี้ควรส่งคืน True สำหรับทุกการลอยยกเว้น Inf และ NaN

แต่วิธีนี้ใช้ไม่ได้ผลเพราะสำหรับโฟลตขนาดใหญ่เพียงพอให้x-1 == xส่งคืนจริง ตัวอย่างเช่น,2.0**54 - 1 == 2.0**54


3

ผมคิดว่าวิธีการแก้ปัญหาของคุณเป็นเรื่องปกติ แต่มีคือการดำเนินงานที่ถูกต้อง regexp

ดูเหมือนจะมีจำนวนมากเกลียด regexp ต่อคำตอบเหล่านี้ซึ่งฉันคิดว่าไม่เป็นธรรม regexps สามารถสะอาดและถูกต้องและรวดเร็วพอสมควร มันขึ้นอยู่กับสิ่งที่คุณพยายามจะทำ คำถามเดิมคือวิธีที่คุณสามารถ "ตรวจสอบว่าสตริงสามารถแสดงเป็นตัวเลข (ลอย)" (ตามชื่อของคุณ) สันนิษฐานว่าคุณต้องการใช้ตัวเลข / ค่าลอยเมื่อคุณตรวจสอบว่าถูกต้องซึ่งในกรณีของคุณลอง / ยกเว้นทำให้รู้สึกมาก แต่ถ้าด้วยเหตุผลบางอย่างคุณแค่ต้องการตรวจสอบว่าสตริงเป็นตัวเลขจากนั้น regex ก็ใช้งานได้ดี แต่ก็ยากที่จะแก้ไข ฉันคิดว่าส่วนใหญ่ของคำตอบ regex เพื่อให้ห่างไกลเช่นอย่าแยกสตริงอย่างถูกต้องโดยไม่มีส่วนจำนวนเต็ม (เช่น ".7") ซึ่งเป็นลอยเท่าที่เกี่ยวข้องกับงูหลาม และเป็นเรื่องยากเล็กน้อยที่จะตรวจสอบใน regex เดียวโดยไม่ต้องใช้ส่วนที่เป็นเศษส่วน ฉันได้รวมสอง regex เพื่อแสดงสิ่งนี้

มันทำให้เกิดคำถามที่น่าสนใจว่า "ตัวเลข" คืออะไร คุณรวม "inf" ที่ถูกต้องเป็นทุ่นในหลามหรือไม่? หรือคุณรวมถึงตัวเลขที่เป็น "ตัวเลข" แต่อาจไม่สามารถแสดงเป็นไพ ธ อนได้ (เช่นตัวเลขที่มีขนาดใหญ่กว่าค่าลอยตัวสูงสุด)

นอกจากนี้ยังมีความคลุมเครือในการแยกวิเคราะห์ตัวเลข ตัวอย่างเช่นอะไรที่เกี่ยวกับ "--20" นี่คือ "หมายเลข" หรือไม่ นี่เป็นวิธีทางกฎหมายในการแสดง "20" หรือไม่ Python จะอนุญาตให้คุณทำ "var = --20" และตั้งค่าเป็น 20 (แม้ว่าจริงๆแล้วนี่เป็นเพราะมันถือว่าเป็นนิพจน์) แต่ float ("- 20") ไม่ทำงาน

Anyways โดยไม่มีข้อมูลเพิ่มเติมที่นี่เป็น regex ที่ผมเชื่อว่าครอบคลุม ints ทั้งหมดและลอยเป็นแยกวิเคราะห์หลามพวกเขา

# Doesn't properly handle floats missing the integer part, such as ".7"
SIMPLE_FLOAT_REGEXP = re.compile(r'^[-+]?[0-9]+\.?[0-9]+([eE][-+]?[0-9]+)?$')
# Example "-12.34E+56"      # sign (-)
                            #     integer (12)
                            #           mantissa (34)
                            #                    exponent (E+56)

# Should handle all floats
FLOAT_REGEXP = re.compile(r'^[-+]?([0-9]+|[0-9]*\.[0-9]+)([eE][-+]?[0-9]+)?$')
# Example "-12.34E+56"      # sign (-)
                            #     integer (12)
                            #           OR
                            #             int/mantissa (12.34)
                            #                            exponent (E+56)

def is_float(str):
  return True if FLOAT_REGEXP.match(str) else False

ตัวอย่างค่าทดสอบ:

True  <- +42
True  <- +42.42
False <- +42.42.22
True  <- +42.42e22
True  <- +42.42E-22
False <- +42.42e-22.8
True  <- .42
False <- 42nope

การรันโค้ดการเปรียบเทียบในคำตอบของ @ ron-reiter แสดงให้เห็นว่าจริง ๆ แล้ว regex นี้เร็วกว่า regex ปกติและเร็วกว่ามากในการจัดการค่าที่ไม่ดีกว่าข้อยกเว้นซึ่งทำให้รู้สึกบางอย่าง ผล:

check_regexp with good floats: 18.001921
check_regexp with bad floats: 17.861423
check_regexp with strings: 17.558862
check_correct_regexp with good floats: 11.04428
check_correct_regexp with bad floats: 8.71211
check_correct_regexp with strings: 8.144161
check_replace with good floats: 6.020597
check_replace with bad floats: 5.343049
check_replace with strings: 5.091642
check_exception with good floats: 5.201605
check_exception with bad floats: 23.921864
check_exception with strings: 23.755481

หวังว่าถูกต้อง - ชอบที่จะได้ยินเกี่ยวกับตัวอย่างที่เคาน์เตอร์ใด ๆ :)
David Ljung Madison Stellar

2
import re
def is_number(num):
    pattern = re.compile(r'^[-+]?[-0-9]\d*\.\d*|[-+]?\.?[0-9]\d*$')
    result = pattern.match(num)
    if result:
        return True
    else:
        return False


​>>>: is_number('1')
True

>>>: is_number('111')
True

>>>: is_number('11.1')
True

>>>: is_number('-11.1')
True

>>>: is_number('inf')
False

>>>: is_number('-inf')
False

2
คุณไม่คิดว่า1e6จะเป็นตัวแทนของตัวเลขหรือไม่?
Mark Dickinson

1

นี่เป็นวิธีง่ายๆในการทำของฉัน สมมติว่าฉันวนลูปผ่านสตริงและฉันต้องการเพิ่มลงในอาร์เรย์ถ้าพวกเขากลายเป็นตัวเลข

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

แทนที่ myvar.apppend ด้วยการดำเนินการใด ๆ ที่คุณต้องการทำกับสตริงหากปรากฎเป็นตัวเลข แนวคิดคือพยายามใช้การดำเนินการ float () และใช้ข้อผิดพลาดที่ส่งคืนเพื่อพิจารณาว่าสตริงเป็นตัวเลขหรือไม่


คุณควรย้ายส่วนต่อท้ายของฟังก์ชั่นนั้นไปไว้ในคำสั่ง else เพื่อหลีกเลี่ยงการทำให้เกิดข้อยกเว้นโดยไม่ตั้งใจถ้ามีบางอย่างผิดปกติกับอาเรย์
DarwinSurvivor

1

ฉันยังใช้ฟังก์ชั่นที่คุณพูดถึง แต่ในไม่ช้าฉันก็สังเกตเห็นว่าสตริงเป็น "น่าน", "Inf" และความแปรผันของมันถือเป็นตัวเลข ดังนั้นฉันจึงเสนอให้คุณปรับปรุงเวอร์ชันของฟังก์ชั่นของคุณซึ่งจะส่งคืนค่าเท็จในประเภทอินพุตเหล่านั้นและจะไม่ล้มเหลว "1e3" ชุดรูปแบบ:

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

1

รหัสนี้จัดการ exponents, float และจำนวนเต็มโดยใช้ regex

return True if str1.lstrip('-').replace('.','',1).isdigit() or float(str1) else False

1

ฟังก์ชั่นตัวช่วยผู้ใช้:

def if_ok(fn, string):
  try:
    return fn(string)
  except Exception as e:
    return None

แล้วก็

if_ok(int, my_str) or if_ok(float, my_str) or if_ok(complex, my_str)
is_number = lambda s: any([if_ok(fn, s) for fn in (int, float, complex)])

0

คุณสามารถพูดคุยเรื่องเทคนิคข้อยกเว้นในวิธีที่มีประโยชน์ได้โดยคืนค่าที่เป็นประโยชน์มากกว่าจริงและเท็จ ตัวอย่างเช่นฟังก์ชั่นนี้จะใส่อัญประกาศรอบสตริง แต่ปล่อยตัวเลขเพียงอย่างเดียว ซึ่งเป็นสิ่งที่ฉันต้องการสำหรับตัวกรองที่รวดเร็วและสกปรกเพื่อให้คำจำกัดความตัวแปรสำหรับ 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:]), ')'

0

ฉันกำลังทำงานกับปัญหาที่ทำให้ฉันไปที่หัวข้อนี้คือวิธีการแปลงชุดข้อมูลเป็นสตริงและตัวเลขในวิธีที่ง่ายที่สุด ฉันรู้หลังจากอ่านรหัสต้นฉบับว่าสิ่งที่ฉันต้องการแตกต่างกันสองวิธี:

1 - ฉันต้องการผลลัพธ์จำนวนเต็มถ้าสตริงแสดงจำนวนเต็ม

2 - ฉันต้องการตัวเลขหรือสตริงผลลัพธ์เพื่อติดกับโครงสร้างข้อมูล

ดังนั้นฉันจึงดัดแปลงรหัสดั้งเดิมเพื่อสร้างอนุพันธ์นี้:

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


0
def is_float(s):
    if s is None:
        return False

    if len(s) == 0:
        return False

    digits_count = 0
    dots_count = 0
    signs_count = 0

    for c in s:
        if '0' <= c <= '9':
            digits_count += 1
        elif c == '.':
            dots_count += 1
        elif c == '-' or c == '+':
            signs_count += 1
        else:
            return False

    if digits_count == 0:
        return False

    if dots_count > 1:
        return False

    if signs_count > 1:
        return False

    return True
โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.