2015-10-02 2 views
0

Я создаю веб-приложение с целью регистрации всех вызовов, сделанных пользователями. Вызов может иметь услугу, номер и стоимость. Ниже приведен код, приведенный ниже (с номерами, обращенными в регулярные выражения), но это несколько беспорядок, и я бы хотел его оптимизировать. Поскольку этот код должен быть точно в этом порядке работать, когда я использовал словарь для хранения выражений и служб регулярного выражения, он не работал. Вот мой текущий код с регулярным выражением используется:Оптимизация кода Python с регулярными выражениями

if (service=='R'): 
     return "ROAMING" 
    elif (service=='V O') or ((service=='S') and (float(cost)==0.0)): 
     return "ONNET" 
    elif (service=="") and (nr_called==""): 
     return "INTERNET" 
    elif (service=='I')or (service=='ROAMING - MMS'):   
     return "OTHERSERV"   
    elif (service=='Internet') or (service=='WAP') or service==('BLACKBERRY.NET') or (service=='ROAMING - INTERNET')or (service=='ROAMING - BLACKBERRY'): 
     return "INTERNET" 
    elif ((nr_called[:6]=="003516" or nr_called[:6]=="003514" or nr_called[:6]=="003511" or nr_called[:6]=="003517" or nr_called[:6]=="003518") or (nr_called[0]=="6" or nr_called[0]=="4" or nr_called[0]=="1" or nr_called[0]=="7" or nr_called[0]=="8")) and (service!="V O"): 
     return "OTHERSERV"  
    elif (service=='Vi F') or (service=='Si'): 
     return "INTERNATIONAL" 
    elif (nr_called[0]=="9" or nr_called[:6]=="003519") and (service=="Vp F") and (float(cost)>0) :   
     return "INS" 
    elif (nr_called[:9]=="003519220" or nr_called[:8]=="00351924" or nr_called[:8]=="00351925" or nr_called[:8]=="00351926" or nr_called[:8]=="00351927" or nr_called[:4]=="9220" or nr_called[:3]=="924" or nr_called[:3]=="925" or nr_called[:3]=="926" or nr_called[:3]=="927") :   
     return "INS" 
    elif ((len(nr_called)==9) and nr_called[:2]=="96") or (nr_called[:7]=="0035196"): 
     return "INS" 
    elif (nr_called[:3]=="921" or nr_called[:8]=="00351921"): 
     return "91" 
    elif (nr_called[:3]=="929" or nr_called[:8]=="00351929"): 
     return "93" 
    elif (nr_called[:3]=="922" or nr_called[:8]=="00351922"): 
     return "OTHERSERV" 
    elif (service!="Vp F") and ((nr_called[:2]=="96") or(nr_called[:7]=="0035196")):    
     return "INS" 
    elif (len(nr_called)==7) or (service=='V O'):   
     return "ONNET" 
    elif ((len(nr_called)==9) and nr_called[:2]=="91") or (nr_called[:7]=="0035191"): 
     return "91" 
    elif ((len(nr_called)==9) and nr_called[:2]=="93") or (nr_called[:7]=="0035193"): 
     return "93" 
    elif ((len(nr_called)==9) and nr_called[:1]=="2") or (nr_called[:5]=="00352"): 
     return "PT" 
    elif float(cost)>0: 
     return "OTHERSERV" 
    else: 
     return "OTHERSERV" 

Количество регулярные выражения:

OTHERSERV: ['(\+*0*351)?922','(\+*0*351)?[146-8]'] 
96:  ['(\+*0*351)?92([4-7|20])','(\+*0*351)?96'] 
93:  ['(\+*0*351)?929','(\+*0*351)?93'] 
91:  ['(\+*0*351)?921','(\+*0*351)?91'] 
PT:  ['(\+*0*351)?2'] 

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

+1

Try OrderdDict: https://docs.python.org/2/library/collections.html#collections.OrderedDict –

+0

Поместите последовательность шаблонов в списке, то вы контролируете/знаете, заказ. Предположительно, вы можете нормализовать числа, начинающиеся с 0 или + для ровно 9 цифр, тогда шаблон числа всегда можно применить как «^ 00351», наиболее сложным является проверка стоимости = 0 или> 0, но как последний тест на стоимость> 0 не влияет на результат, вы всегда можете добавить флаг, чтобы проверить стоимость == 0, используемую только для теста service = 'S'. Однако таблица не всегда удобна в обслуживании. Почему вы используете elif, когда каждый тест включает оператор возврата? – barny

ответ

1

Я не уверен, я понимаю, что вы имеете в виду о регулярных выражений, но один вариант для очистки, если/список Элиф будет использовать список результата/проверки кортежи:

actions = [ 
    ('ROAMING' , lambda service,nr_called,cost: service=='R'), 
    ('ONNET' , lambda service,nr_called,cost: service in ('V O','S') and float(cost)==0.0), 
    ('INTERNET' , lambda service,nr_called,cost: service=='' and nr_called==''), 
    ('OTHERSERV', lambda service,nr_called,cost: service in ('I','ROAMING - MMS')) 

    # fallthrough 
    ('OTHERSERV', lambda service_nr_called,cost: True) 
] 

for value,check in actions: 
    if check(service,nr_called,cost): 
    return value 

# fallthrough 
return 'OTHERSERV' 

Необходим один или другие элементы, обозначенные как «провал».

1

Я думал о решении, которое является чем @ryachza предложением более полно данных/приводится таблица-, например:

import re 

def oldcategorize(service, nr_called, cost): 
    if (service=='R'): 
     return "ROAMING" 
    elif (service=='V O') or ((service=='S') and (float(cost)==0.0)): 
     return "ONNET" 
    elif (service=="") and (nr_called==""): 
     return "INTERNET" 
    elif (service=='I')or (service=='ROAMING - MMS'):   
     return "OTHERSERV"   
    elif (service=='Internet') or (service=='WAP') or service==('BLACKBERRY.NET') or (service=='ROAMING - INTERNET')or (service=='ROAMING - BLACKBERRY'): 
     return "INTERNET" 
    elif ((nr_called[:6]=="003516" or nr_called[:6]=="003514" or nr_called[:6]=="003511" or nr_called[:6]=="003517" or nr_called[:6]=="003518") or (nr_called[0]=="6" or nr_called[0]=="4" or nr_called[0]=="1" or nr_called[0]=="7" or nr_called[0]=="8")) and (service!="V O"): 
     return "OTHERSERV"  
    elif (service=='Vi F') or (service=='Si'): 
     return "INTERNATIONAL" 
    elif (nr_called[0]=="9" or nr_called[:6]=="003519") and (service=="Vp F") and (float(cost)>0) :   
     return "INS" 
    elif (nr_called[:9]=="003519220" or nr_called[:8]=="00351924" or nr_called[:8]=="00351925" or nr_called[:8]=="00351926" or nr_called[:8]=="00351927" or nr_called[:4]=="9220" or nr_called[:3]=="924" or nr_called[:3]=="925" or nr_called[:3]=="926" or nr_called[:3]=="927") :   
     return "INS" 
    elif ((len(nr_called)==9) and nr_called[:2]=="96") or (nr_called[:7]=="0035196"): 
     return "INS" 
    elif (nr_called[:3]=="921" or nr_called[:8]=="00351921"): 
     return "91" 
    elif (nr_called[:3]=="929" or nr_called[:8]=="00351929"): 
     return "93" 
    elif (nr_called[:3]=="922" or nr_called[:8]=="00351922"): 
     return "OTHERSERV" 
    elif (service!="Vp F") and ((nr_called[:2]=="96") or(nr_called[:7]=="0035196")):    
     return "INS" 
    elif (len(nr_called)==7) or (service=='V O'):   
     return "ONNET" 
    elif ((len(nr_called)==9) and nr_called[:2]=="91") or (nr_called[:7]=="0035191"): 
     return "91" 
    elif ((len(nr_called)==9) and nr_called[:2]=="93") or (nr_called[:7]=="0035193"): 
     return "93" 
    elif ((len(nr_called)==9) and nr_called[:1]=="2") or (nr_called[:5]=="00352"): 
     return "PT" 
    elif float(cost)>0: 
     return "OTHERSERV" 
    else: 
     return "OTHERSERV" 
    return "FAILED" 

# table of categories with regex criteria 
# special treatment of first character of a pattern "-" means NOT matching 
# note cost is coverted to standardized format using str() for matching 
#  service     number  cost category 
categories = [ 
    # if (service=='R'): 
    #  return "ROAMING" 
    ["^R$"      ,""   ,""   ,"ROAMING"] 
    # elif (service=='V O') or ((service=='S') and (float(cost)==0.0)): 
    #  return "ONNET" 
    ,["^V O$"     ,""   ,""   ,"ONNET"] 
    ,["^S$"      ,""   ,"^0.0$" ,"ONNET"] 
    # elif (service=="") and (nr_called==""): 
    # return "INTERNET" 
    ,["^$"      ,"^$"  ,""   ,"INTERNET"] 
    # elif (service=='I')or (service=='ROAMING - MMS'):   
    #  return "OTHERSERV"   
    ,["^I$"      ,""   ,""   ,"OTHERSERV"] 
    ,["^ROAMING - MMS$"   ,""   ,""   ,"OTHERSERV"] 
    # elif (service=='Internet') or (service=='WAP') or service==('BLACKBERRY.NET') or (service=='ROAMING - INTERNET')or (service=='ROAMING - BLACKBERRY'): 
    #  return "INTERNET" 
    ,["^Internet"    ,""   ,""   ,"INTERNET"] 
    ,["^WAP"      ,""   ,""   ,"INTERNET"] 
    ,["^BLACKBERRY.NET"   ,""   ,""   ,"INTERNET"] 
    ,["^ROAMING - INTERNET"  ,""   ,""   ,"INTERNET"] 
    ,["^ROAMING - INTERNET"  ,""   ,""   ,"INTERNET"] 
    ,["^ROAMING - INTERNET"  ,""   ,""   ,"INTERNET"] 
    ,["^ROAMING - BLACKBERRY" ,""   ,""   ,"INTERNET"] 
    # elif ((nr_called[:6]=="003516" or nr_called[:6]=="003514" or nr_called[:6]=="003511" or nr_called[:6]=="003517" or nr_called[:6]=="003518") or (nr_called[0]=="6" or nr_called[0]=="4" or nr_called[0]=="1" or nr_called[0]=="7" or nr_called[0]=="8")) and (service!="V O"): 
    #  return "OTHERSERV" 
    ,["-^V O"     ,"^00351[14678]" ,""   ,"OTHERSERV"] 
    ,["-^V O"     ,"^[15678]"   ,""   ,"OTHERSERV"] 
    # elif (len(nr_called)==7) or (service=='V O'):   
    #  return "ONNET" 
    ,[""      ,"^.......$" ,""   ,"ONNET"] 
    ,["^V O$"      ,""    ,""   ,"ONNET"] 
    # ((len(nr_called)==9) and nr_called[:2]=="91") or (nr_called[:7]=="0035191"): 
    #  return "91" 
    ,[""      ,"^91.......$" ,""   ,"91"] 
    ,[""      ,"^0035191"  ,""   ,"91"] 
] 

def newcategorize(service, nr_called, cost): 
    for servpat,numpat,costpat,res in categories: 
     print servpat,numpat,costpat,res 
     if (servpat[0]=="-" and not re.match(servpat[1:],service)) or re.match(servpat,service): 
      if (numpat[0]=="-" and not re.match(numpat[1:],nr_called)) or re.match(numpat,nr_called): 
       if (costpat[0]=="-" and not re.match(costpat[1:],str(cost))) or re.match(costpat,str(cost)): 
        return res 
    result = "FAILED to find %s %s %s"%(service,nr_called, cost) 
    # print result 
    return result 

testdata = [ 
    ["x","",0.0] 
    ,["S","123",0.0] 
    ,["NOT V O","003517",0.0] 
] 

for s,n,c in testdata: 
    oc = oldcategorize(s,n,c) 
    nc = oldcategorize(s,n,c) 
    if oc != nc: 
     print "ERROR",s,n,c,oc,nc 
    print "match",s,n,c,oc,nc 

Так таблица содержит все данные, необходимые для приведения в действие логики, но логика сам кодируется в функции newcategorize(), используя силу регулярных выражений, чтобы выполнить большую часть тяжелой работы, и только добавление, что ведущий - в шаблоне заставляет логику искать соответствие шаблона NOT. Используя этот подход, таблица является более кратким, тогда как при решении @ryachza таблица может быть довольно трудной для чтения и, вероятно, отладки для более сложных лямбда-выражений. При моем подходе вы просто добавляете утверждения печати.

НТН Barny

+0

Мне очень нравится эта концепция! Очевидным компромиссом является избыточность от расщепления «или» условий, теряющих связь, и необходимость реструктуризации, например. '(x или y) и z' to' (x и z) или (y и z) ', позволяя' z' изменять независимо. Я думаю, что это решение, безусловно, стоит рассмотреть на основе общего контекста проблемы. – ryachza

Смежные вопросы