2008-09-28 8 views
7

मेरा लक्ष्य यहां एक बहुत ही सरल टेम्पलेट भाषा बनाना है। पल में, मैं एक मूल्य के साथ एक चर की जगह पर काम कर रहा हूँ, इस तरह:मैं पाइथन रेगेक्स को अपराधी रूप से अक्षम तरीके से उपयोग कर रहा हूं

इस इनपुट:

वेब

इस उत्पादन का उत्पादन करना चाहिए:

वेब यह एक टेस्ट वैरिएबल

मुझे यह काम मिल गया है। लेकिन मेरे कोड को देखते हुए, मैं एक ही स्ट्रिंग पर कई समान रेगेक्स चला रहा हूं - जो कि मेरी दक्षता की भावना को अपमानित करता है। एक बेहतर, अधिक पाइथोनिक तरीका होना चाहिए। (यह दो "जबकि" लूप है जो वास्तव में अपमान करते हैं।)

यह यूनिट परीक्षण पास करता है, इसलिए यदि यह मूर्खतापूर्ण समयपूर्व अनुकूलन है, तो मुझे बताएं - मैं इसे जाने के लिए तैयार हूं। दस्तावेज़ में इन परिवर्तनीय परिभाषाओं और उपयोगों में से कई दर्जन हो सकते हैं, लेकिन सैकड़ों नहीं। लेकिन मुझे संदेह है कि इसमें सुधार करने के लिए स्पष्ट (अन्य लोगों के) तरीके हैं, और मैं उत्सुक हूं कि स्टैक ओवरफ्लो भीड़ के साथ क्या होगा।

def stripMatchedQuotes(item): 
    MatchedSingleQuotes = re.compile(r"'(.*)'", re.LOCALE) 
    MatchedDoubleQuotes = re.compile(r'"(.*)"', re.LOCALE) 
    item = MatchedSingleQuotes.sub(r'\1', item, 1) 
    item = MatchedDoubleQuotes.sub(r'\1', item, 1) 
    return item 




def processVariables(item): 
    VariableDefinition = re.compile(r'<%(.*?)=(.*?)%>', re.LOCALE) 
    VariableUse = re.compile(r'<%(.*?)%>', re.LOCALE) 
    Variables={} 

    while VariableDefinition.search(item): 
     VarName, VarDef = VariableDefinition.search(item).groups() 
     VarName = stripMatchedQuotes(VarName).upper().strip() 
     VarDef = stripMatchedQuotes(VarDef.strip()) 
     Variables[VarName] = VarDef 
     item = VariableDefinition.sub('', item, 1) 

    while VariableUse.search(item): 
     VarName = stripMatchedQuotes(VariableUse.search(item).group(1).upper()).strip() 
     item = VariableUse.sub(Variables[VarName], item, 1) 

    return item 
+0

दुनिया को एक और पायथन टेम्पलेट भाषा की आवश्यकता नहीं है। पहले से ही दर्जनों मौजूद हैं। क्या आप उनमें से किसी एक का उपयोग नहीं कर सकते? –

+0

@ स्कोफ: क्या मैं आपको http://genshi.edgewall.org/ पर इंगित कर सकता हूं जो आपके जीवन के केक बना देगा। – user7116

+1

मुझे हंसी बनाने के लिए शीर्षक +1 पसंद है। अकेले शीर्षक के लिए – UnkwnTech

उत्तर

10

चीजों को बेहतर बनाने वाली पहली चीज़ फ़ंक्शन के बाहर re.compile को स्थानांतरित करना है। संकलन कैश किया गया है, लेकिन यह जांचने में एक गति हिट है कि यह संकलित है या नहीं।

MatchedQuotes = re.compile(r"(['\"])(.*)\1", re.LOCALE) 
item = MatchedQuotes.sub(r'\2', item, 1) 

अंत में, आप processVariables में regex में इस गठजोड़ कर सकते हैं:

एक और संभावना के रूप में नीचे एक भी regex का उपयोग करने के लिए है। Re.sub के लिए फ़ंक्शन का उपयोग करने के लिए Torsten Marek's सुझाव लेना, यह नाटकीय रूप से चीजों को बेहतर और सरल बनाता है।

VariableDefinition = re.compile(r'<%(["\']?)(.*?)\1=(["\']?)(.*?)\3%>', re.LOCALE) 
VarRepl = re.compile(r'<%(["\']?)(.*?)\1%>', re.LOCALE) 

def processVariables(item): 
    vars = {} 
    def findVars(m): 
     vars[m.group(2).upper()] = m.group(4) 
     return "" 

    item = VariableDefinition.sub(findVars, item) 
    return VarRepl.sub(lambda m: vars[m.group(2).upper()], item) 

print processVariables('<%"TITLE"="This Is A Test Variable"%>The Web <%"TITLE"%>') 

यहाँ 100000 रन के लिए मेरे समय कर रहे हैं:

Original  : 13.637 
Global regexes : 12.771 
Single regex : 9.095 
Final version : 1.846 

[संपादित करें] लापता गैर लालची विनिर्देशक जोड़े

[EDIT2] जोड़े गए।ऊपरी() कॉल मूल संस्करण

+0

अच्छा काम, मेरा वोट मिलता है! –

2

अपनी खुद की प्रोग्रामिंग भाषा कभी न बनाएं। कभी। (मुझे इस नियम का अपवाद था, लेकिन अब और नहीं।)

हमेशा एक मौजूदा भाषा है जिसका उपयोग आप कर सकते हैं जो आपकी आवश्यकताओं को बेहतर बनाता है। यदि आपने अपने उपयोग-मामले पर विस्तार से बताया है, तो लोग आपको उपयुक्त भाषा चुनने में मदद कर सकते हैं।

+0

डोमेन-विशिष्ट भाषा निर्माण करना उचित है, यदि यह उचित है। नेवर से नेवर। – skaffman

+0

यह हो सकता है, लेकिन पाइथन में टेक्स्ट टेम्पलेटिंग भाषाओं के लिए पहले से ही एक अरब अच्छे विकल्प हैं ... –

+4

मेरे कारणों का एक हिस्सा यह है कि मैं अपने कौशल को बढ़ाऊं। अगर ऐसा कुछ था जिसके लिए मुझे भुगतान मिल रहा था, तो मैं आपके सुझाव का पालन करता हूं और इसे सबसे तेज़ तरीका करता हूं।जैसा कि मैं सीखने को अधिकतम करने की कोशिश कर रहा हूं, प्रोग्रामर दक्षता नहीं। – Schof

1

आप r"(\"|')(.*?)\1" के साथ एक ही समय में दोनों प्रकार के उद्धरणों से मेल खा सकते हैं - \1 पहले समूह को संदर्भित करता है, इसलिए यह केवल मेल खाने वाले उद्धरणों से मेल खाता है।

0

पंक्ति में दो बार खोज न करें (लूप सशर्त में, और लूप में पहला कथन)। लूप से पहले एक बार कॉल करें (और परिणाम कैश करें), और उसके बाद लूप के अंतिम विवरण में।

1

आप re.compile को थोड़ा सा कॉल कर रहे हैं। इनके लिए एक वैश्विक चर यहां चोट नहीं पहुंचाएगा।

3

sub जैसी सरल असंवेदनशील स्थिति को सरल स्ट्रिंग की बजाय तर्क के रूप में कॉल करने योग्य ले सकता है। कि का उपयोग करके आप एक समारोह कॉल के साथ सभी चर की जगह ले सकता:

>>> import re 
>>> var_matcher = re.compile(r'<%(.*?)%>', re.LOCALE) 
>>> string = '<%"TITLE"%> <%"SHMITLE"%>' 
>>> values = {'"TITLE"': "I am a title.", '"SHMITLE"': "And I am a shmitle."} 
>>> var_matcher.sub(lambda m: vars[m.group(1)], string) 
'I am a title. And I am a shmitle. 

eduffy.myopenid.com की सलाह का पालन और संकलित regexes के आसपास रहते हैं।

वही नुस्खा पहले लूप पर लागू किया जा सकता है, केवल वहां आपको पहले चर के मान को स्टोर करने की आवश्यकता है, और प्रतिस्थापन के रूप में हमेशा "" लौटाएं।

1

यदि किसी रेगेक्स में केवल एक है। * वाइल्डकार्ड और शाब्दिक, तो आप खोलने और बंद करने वाले डिलीमीटरों का पता लगाने के लिए खोज और rfind का उपयोग कर सकते हैं।

यदि इसमें केवल एक श्रृंखला शामिल है। *? वाइल्डकार्ड, और शाब्दिक, तो आप काम करने के लिए खोज की एक श्रृंखला का उपयोग कर सकते हैं।

यदि कोड समय-महत्वपूर्ण है, तो यह स्विच regexp से पूरी तरह से दूर हो सकती है और थोड़ी अधिक गति दे सकती है।

इसके अलावा, मुझे लगता है कि यह LL-parsable language है। आप एक पुस्तकालय की तलाश कर सकते हैं जो आपके लिए ऐसी चीजों को पहले से ही पार्स कर सकता है। आप एक-पास पार्स करने के लिए रिकर्सिव कॉल का भी उपयोग कर सकते हैं - उदाहरण के लिए, आप अपनी प्रक्रिया को लागू कर सकते हैं वैरिएबल फ़ंक्शन केवल पहले उद्धरण का उपभोग करने के लिए, और उसके बाद उद्धरण-मिलान फ़ंक्शन को अगले उद्धरण आदि का उपभोग करने के लिए कॉल करें।

2

एक templating भाषा बनाना सभी अच्छी और अच्छी है, लेकिन templating भाषा के लक्ष्यों में से एक लक्ष्य आसान पठनीयता और कुशल पार्सिंग नहीं होना चाहिए? आपके द्वारा दिया गया उदाहरण न तो लगता है।

जेमी Zawinsky के रूप में प्रसिद्धि से कहा:

कुछ लोगों को जब एक समस्या के साथ सामना किया, लगता है कि "मैं जानता हूँ कि, मैं रेगुलर एक्सप्रेशन का उपयोग करेंगे!" अब उनके पास दो समस्याएं हैं।

यदि नियमित अभिव्यक्ति आपके द्वारा बनाई गई किसी समस्या का समाधान है, तो सर्वोत्तम शर्त एक बेहतर नियमित अभिव्यक्ति लिखना नहीं है, बल्कि अपने उपयोग को पूरी तरह समाप्त करने के लिए अपने दृष्टिकोण को फिर से डिजाइन करना है। नियमित अभिव्यक्ति जटिल, महंगे, बनाए रखने के लिए बेहद मुश्किल हैं, और (आदर्श) केवल किसी अन्य व्यक्ति द्वारा बनाई गई किसी समस्या के आसपास काम करने के लिए उपयोग की जानी चाहिए।

+0

सिद्धांत रूप में, मैं सहमत हूं। हमें उपयोगकर्ता सेवा पर जाना चाहिए और जब भी कोई कोई प्रश्न लिखता है और उसे "रेगेक्स" टैग देता है तो यह उद्धरण दिखाने के लिए मजबूर होना चाहिए। –

+0

मुझे उत्सुकता है कि आपको लगता है कि उदाहरण में न तो आसान पठनीयता या कुशल पार्सिंग है? मैं इसे और अधिक पठनीय और पार्स करने में आसान बनाने के लिए क्या बदल सकता हूं? – Schof

-3

अपनी खुद की टेम्पलेट भाषा बनाने के बजाय एक्सएमएल और एक्सएसएलटी का उपयोग क्यों नहीं करें? आप जो करना चाहते हैं वह एक्सएसएलटी में बहुत आसान है।

1

Mako का उपयोग क्यों नहीं करें? गंभीरता से। मको के पास आपकी क्या आवश्यकता नहीं है? शायद आप पहले से काम करने वाले कुछ को अनुकूलित या विस्तारित कर सकते हैं।

संबंधित मुद्दे

 संबंधित मुद्दे