2009-11-03 40 views
13

Python thích nâng cao ngoại lệ, điều này thường tuyệt vời. Nhưng tôi đang phải đối mặt với một số chuỗi tôi tuyệt vọng muốn chuyển đổi sang số nguyên bằng cách sử dụng ngữ nghĩa atoi/atof của C - ví dụ: atoi của "3 của 12", "3/12", "3/12", tất cả sẽ trở thành 3; atof ("3,14 giây") nên trở thành 3,14; atoi ("-99 điểm") nên trở thành -99. Tất nhiên Python có các hàm atoi và atof, không hoạt động như atoi và atof và chính xác giống như các hàm tạo int và float của Python.Python tương đương với atoi/atof

Điều tốt nhất tôi có cho đến nay, đó là thực sự xấu xí và khó có thể mở rộng sang các định dạng phao khác nhau có sẵn:

value = 1 
s = str(s).strip() 
if s.startswith("-"): 
    value = -1 
    s = s[1:] 
elif s.startswith("+"): 
    s = s[1:] 
try: 
    mul = int("".join(itertools.takewhile(str.isdigit, s))) 
except (TypeError, ValueError, AttributeError): 
    mul = 0 
return mul * value 

Trả lời

3

Nó khá đơn giản để làm điều này với biểu thức thông thường:

>>> import re 
>>> p = re.compile(r'[^\d-]*(-?[\d]+(\.[\d]*)?([eE][+-]?[\d]+)?)') 
>>> def test(seq): 
     for s in seq: 
      m = p.match(s) 
      if m: 
       result = m.groups()[0] 
       if "." in result or "e" in result or "E" in result: 
        print "{0} -> {1}".format(s, float(result)) 
       else: 
        print '"{0}" -> {1}'.format(s, int(result)) 
      else: 
       print s, "no match" 

>>> test(s) 
"1 0" -> 1 
"3 of 12" -> 3 
"3 1/2" -> 3 
"3/12" -> 3 
3.15 seconds -> 3.15 
3.0E+102 -> 3e+102 
"what about 2?" -> 2 
"what about -2?" -> -2 
2.10a -> 2.1 
+1

' atoi ("những gì về 2") 'nên trả về' 0', vì nó bắt đầu với một 'w 'và' w' không phải là chữ số. – Quuxplusone

6

Có lẽ sử dụng một regex nhanh chóng để lấy chỉ là phần đầu tiên của chuỗi có thể được được coi là số? Một cái gì đó giống như ...

-?[0-9]+(?:\.[0-9]+)? 

cho phao nổi và cho ints chỉ,

-?[0-9]+ 
+3

float có thể có 'e' hoặc' E' trong chúng cũng –

7

Tôi nghĩ rằng phiên bản lặp đi lặp lại là tốt hơn so với phiên bản đệ quy

# Iterative 
def atof(s): 
    s,_,_=s.partition(' ') # eg. this helps by trimming off at the first space 
    while s: 
     try: 
      return float(s) 
     except: 
      s=s[:-1] 
    return 0.0 

# Recursive 
def atof(s): 
    try: 
     return float(s) 
    except: 
     if not s: 
      return 0.0 
     return atof(s[:-1]) 


print atof("3 of 12") 
print atof("3/12") 
print atof("3/12") 
print atof("3.14 seconds") 
print atof("314e-2 seconds") 
print atof("-99 score") 
print atof("hello world") 
+0

+1 cho những gì tôi đoán là thuật toán đơn giản nhất mà tôi sẽ thấy ở đây! –

+2

Đơn giản, có lẽ, nhưng không thực sự hiệu quả (đặc biệt nếu phần văn bản của chuỗi dài so với phần số). – Amber

+0

Nếu chuỗi có thể có nhiều rác, bạn sẽ phải sử dụng vòng lặp thay vì đệ quy. Nếu bạn đang thực hiện nhiều chuyển đổi thì có nhiều cách nhanh hơn để thực hiện. –

36

Nếu bạn nên quan tâm để có được chính xác chức năng của atoi của c, tại sao không sử dụng nó trực tiếp? Ví dụ, trên máy Mac của tôi,

>>> import ctypes, ctypes.util 
>>> whereislib = ctypes.util.find_library('c') 
>>> whereislib 
'/usr/lib/libc.dylib' 
>>> clib = ctypes.cdll.LoadLibrary(whereislib) 
>>> clib.atoi('-99foobar') 
-99 

Trong Linux, Windows, vv, mã giống hệt nhau nên làm việc ngoại trừ việc bạn sẽ thấy một con đường khác nếu bạn kiểm tra whereislib (chỉ trên thực sự, thực sự cài đặt đặc biệt nên mã này bao giờ thất bại để tìm thư viện thời gian chạy C).

Nếu bạn muốn tránh sử dụng thư viện C trực tiếp, tôi đoán bạn có thể lấy tiền tố có liên quan, ví dụ: với RE chẳng hạn như r'\s*([+-]?\d+)' và thử int về điều đó.

+2

+1 Câu trả lời hay! –

+0

Đoán của tôi sẽ là lý do lớn nhất chống lại điều này là sự phụ thuộc nền tảng (chưa kể rằng các thư viện về mặt lý thuyết có thể cư trú ở các vị trí khác nhau ngay cả trên cùng một nền tảng). – Amber

+1

@Andrew, tx! @ Dav, có, bạn phải xác định vị trí của libc DLL (nó cũng có thể có tên khác nhau và đường dẫn), nhưng 'ctypes.util.find_library' giúp - Tôi vừa chỉnh sửa câu trả lời để hiển thị như thế nào để sử dụng nó. –

0

Tôi nghĩ rằng tôi sẽ làm điều đó char bởi char:

def myatof(s): 
    try: 
     return float(s); 
    except: 
     last_result = None 
     for i in range(1, len(s)): 
      try: 
       last_result = float(s[:i]) 
      except: 
       return last_result 
    return last_result 
+1

Điều đó không hoạt động đúng cho '314e-2' –

-1

Làm thế nào về điều này?

num=int(q.join(re.findall(r'[\d-]',s))) 
+0

ở đây q = '' ban đầu. s là chuỗi đầu vào num là câu trả lời cuối cùng. – abhilash

Các vấn đề liên quan