2009-04-29 12 views
5

मैं कुछ एक्सएमएल संरचना के माध्यम से चलकर गतिशील रूप से नियमित अभिव्यक्ति उत्पन्न कर रहा हूं और कथन का निर्माण कर रहा हूं क्योंकि मैं अपने नोड प्रकारों के माध्यम से शूट करता हूं। मैं इस नियमित अभिव्यक्ति का उपयोग लेआउट प्रकार के हिस्से के रूप में कर रहा हूं जिसे मैंने परिभाषित किया है। मैं फिर एक पाठ फ़ाइल के माध्यम से विश्लेषण करता हूं जिसमें प्रत्येक पंक्ति की शुरुआत में एक आईडी है। यह आईडी मुझे एक विशिष्ट लेआउट पर इंगित करती है। फिर मैं उस पंक्ति में डेटा को अपने रेगेक्स के खिलाफ मिलान करने का प्रयास करता हूं।गतिशील रूप से निर्मित नियमित अभिव्यक्तियां बहुत धीमी गति से चल रही हैं!

ठीक और बेवकूफ सही लगता है? एकमात्र समस्या यह है कि तारों को बहुत धीमा कर रहा है। मैंने उन्हें कुछ चीजों की कोशिश करने और गति देने के लिए संकलित के रूप में सेट किया है, लेकिन इसका कोई फायदा नहीं हुआ है। परेशान बात यह है कि ये अभिव्यक्ति जटिल नहीं हैं। मैं किसी भी तरह से रेगेक्स गुरु नहीं हूं, लेकिन मुझे सभ्य चीजें अच्छी तरह से चलने के लिए उनके बारे में जानकारी है।

यहाँ कोड है कि भाव उत्पन्न करता है ...

StringBuilder sb = new StringBuilder(); 
//get layout id and memberkey in there... 
sb.Append(@"^([0-9]+)[ \t]{1,2}([0-9]+)"); 
foreach (ColumnDef c in columns) 
{ 
    sb.Append(@"[ \t]{1,2}"); 
    switch (c.Variable.PrimType) 
    { 
     case PrimitiveType.BIT: 
      sb.Append("(0|1)"); 
      break; 
     case PrimitiveType.DATE: 
      sb.Append(@"([0-9]{2}/[0-9]{2}/[0-9]{4})"); 
      break; 
     case PrimitiveType.FLOAT: 
      sb.Append(@"([-+]?[0-9]*\.?[0-9]+)"); 
      break; 
     case PrimitiveType.INTEGER: 
      sb.Append(@"([0-9]+)"); 
      break; 
     case PrimitiveType.STRING: 
      sb.Append(@"([a-zA-Z0-9]*)"); 
      break; 
    } 
} 
sb.Append("$"); 
_pattern = new Regex(sb.ToString(), RegexOptions.Compiled); 

वास्तविक धीमी गति से भाग ...

public System.Text.RegularExpressions.Match Match(string input) 
{ 
    if (input == null) 
     throw new ArgumentNullException("input"); 

    return _pattern.Match(input); 
} 

एक ठेठ "_pattern" 40-50 कॉलम हो सकता है। मैं पूरे पैटर्न चिपकाने से बचाऊंगा। मैं प्रत्येक मामले को समूहबद्ध करने का प्रयास करता हूं ताकि मैं मैच ऑब्जेक्ट में बाद में प्रत्येक मामले पर गणना कर सकूं।

कोई सुझाव या संशोधन जो काफी मदद कर सकता है? या यह धीरे-धीरे उम्मीद की जा रही है?

स्पष्टता के लिए संपादित करें: क्षमा करें, मुझे नहीं लगता कि मैं पहली बार पर्याप्त स्पष्ट था।

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

+0

आप बीआईटी के लिए [01] कोशिश कर सकते हैं। – Dave

+0

क्या आप इस रेगेक्स के साथ सीएसवी से मिलान करने की कोशिश कर रहे हैं? – Gumbo

+0

इसका टैब एसएएस –

उत्तर

8

आप रेगेक्स के साथ 50 कॉलम सीएसवी फ़ाइल (जो टैब का उपयोग करते हैं) को पार्स कर रहे हैं?

आपको डुप्लिकेट टैब को हटा देना चाहिए, फिर टेक्स्ट को \ t पर विभाजित करना चाहिए। अब आपके पास अपने सभी कॉलम सरणी में हैं।आप अपने कॉलमडिफ ऑब्जेक्ट संग्रह का उपयोग करके आपको यह बताने के लिए उपयोग कर सकते हैं कि प्रत्येक कॉलम क्या है।

संपादित करें: एक बार जब आप चीजों को विभाजित है, आप वैकल्पिक regex प्रत्येक मान सत्यापित करने के लिए इस्तेमाल कर सकते हैं, यह बहुत विशाल एकल regex का उपयोग कर से अधिक तेजी से होना चाहिए।

EDIT2: तुम भी वास्तव में क्या स्तंभ (रों) जानने का एक अतिरिक्त लाभ मिलता है बुरी तरह से स्वरूपित है और आप की तरह एक त्रुटि उत्पादन कर सकते हैं "कॉलम 30 में लाइन 12 पर, उम्मीद दिनांक स्वरूप Sytax त्रुटि।"

+0

मुझे लगता है कि यह बहुत तेज़ और सरल होगा। –

+0

यह शायद अब तक का सबसे अच्छा समाधान प्रस्तुत किया गया है।मैं दैनिक आधार पर दर्जनों जटिल regexes का उपयोग (प्रसंस्करण प्रकाशन पाठ और एक्सएमएल)। आईएमई, एक बार आपकी regexes जटिलता के एक निश्चित "महत्वपूर्ण द्रव्यमान" तक पहुंचने के बाद, प्रदर्शन ट्यूबों नीचे चला जाता है। इस समस्या को छोटे हिस्सों में विभाजित करना इस बाधा के आसपास आपका रास्ता होगा। – patjbs

1

डिफ़ॉल्ट रूप से एक अभिव्यक्ति में 50 मिलान समूहों की क्षमता होने से थोड़ा धीमा होने वाला है। मैं यह देखने के लिए कुछ चीजें करता हूं कि आप प्रदर्शन झटके को पिन कर सकते हैं या नहीं।

  1. हार्ड कोडित, गतिशील तुलना की कोशिश करके शुरू करें और देखें कि आपके पास कोई प्रदर्शन लाभ है या नहीं।
  2. अपनी आवश्यकताओं को देखें और देखें कि
  3. का मूल्यांकन करने के लिए आपको आवश्यक समूहों की संख्या को कम करने का कोई तरीका है या नहीं, यदि आवश्यक हो तो एक प्रोफाइलर टूल का उपयोग करें, जैसे मंदी के स्थान को देखने के लिए एंट्स प्रोफाइलर।
2

ठीक है। स्ट्रिंगबिल्डर का उपयोग करके पैटर्न बनाना, उन्हें संयोजित करने की तुलना में कुछ चक्रों को बचाएगा।

कठोर (जिसे स्पष्ट रूप से मापा जा सकता है) पर एक अनुकूलन संभवतः किसी अन्य विधि के माध्यम से ऐसा करने जा रहा है।

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

शायद बड़ी टेक्स्ट फ़ाइल की बजाय किसी अन्य विधि में डेटा संग्रहीत करने के लिए अधिक कुशल होगा (इसके लिए एक्सएमएल का भी उपयोग करें?), या शायद अल्पविराम से अलग सूची।

+0

। यही कारण है कि मैं regex का उपयोग कर रहा हूँ। यह सुनिश्चित करने के लिए कि आयातित डेटा उपयोगकर्ता द्वारा निर्दिष्ट दिए गए प्रारूप को फिट करता है। –

+0

जब आप कहते हैं कि यह धीमा है, तो आपका कितना धीमा मतलब है? ये फाइलें कितनी बड़ी हैं? आप कितने पैटर्न की तुलना कर रहे हैं? संभवतः कुछ सामान्य पैटर्न हैं जो if और substrings का उपयोग करके किया जा सकता है। सामान्य पैटर्न के लिए RegEx का उपयोग करने के बजाए यह शायद अधिक कुशल (हालांकि कम साफ) होगा, तो आप उन्हें ऐप में हार्ड कोड करते हैं। वैसे, क्या यह कार्यक्षमता नियमित रूप से उपयोग की जा रही है, यदि हां, तो इस डेटा को सीधे जहां भी जा रहा है (डेटाबेस?), इनपुट पर सत्यापन करने के लिए एक और प्रभावशाली तरीका होना चाहिए। –

4

नियमित अभिव्यक्ति बनाने के लिए महंगे हैं और यदि आप उन्हें संकलित करते हैं तो और भी महंगे हैं। तो समस्या यह है कि आप कई नियमित अभिव्यक्तियां बना रहे हैं लेकिन केवल एक बार उनका उपयोग करें।

आपको उन्हें पुन: उपयोग के लिए कैश करना चाहिए और अगर आप उन्हें अक्सर उपयोग नहीं करना चाहते हैं तो उन्हें संकलित न करें। मैंने कभी यह सुनिश्चित नहीं किया है, लेकिन मैं कल्पना कर सकता हूं कि संकलन की लागत को कम करने के लिए आपको 100 से अधिक बार एक साधारण नियमित अभिव्यक्ति का उपयोग करना होगा।

प्रदर्शन परीक्षण

  • Regex: "^(?:[a-zA-Z0-9](?:[a-zA-Z0-9-]*[a-zA-Z0-9])?\.)+(?:[a-z]{2}|com|org|net|gov|mil|biz|info|mobi|name|aero|jobs|museum)$"

  • इनपुट: यात्रा प्रति मिलीसेकेंड में "www.stackoverflow.com"

  • परिणाम

    • एक regex , संकलित, 10,000 पुनरावृत्तियों: 0.0018 एमएस
    • एक regex, संकलित नहीं, 10,000 पुनरावृत्तियों: 0.0021 एमएस यात्रा, संकलित नहीं प्रति
    • एक regex, 10,000 पुनरावृत्तियों: 0.0287 एमएस यात्रा प्रति
    • एक regex , संकलित, 10,000 पुनरावृत्तियों: 4.8144 एमएस

ध्यान दें कि 10 के बाद भी, 000 पुनरावृत्तियों संकलित और असम्पीडित रेगेक्स अभी भी उनके प्रदर्शन की तुलना में बहुत करीब हैं। पुनरावृत्तियों की बढ़ती संख्या के साथ संकलित रेगेक्स बेहतर प्रदर्शन करता है।

  • एक regex, संकलित, 1000000 पुनरावृत्तियों: 0.००,१३७ एमएस
  • एक regex, संकलित नहीं, 1000000 पुनरावृत्तियों: 0.००,२२५ एमएस
+0

शायद मुझे थोड़ा बेहतर व्याख्या करने की आवश्यकता है। मैं केवल एक बार उनका उपयोग नहीं कर रहा हूँ। किसी भी समय पार्स की गई फ़ाइल के दौरान कुछ विशिष्ट लेआउट को इंगित करता है। मैं जांचता हूं कि रेखा उस लेआउट के लिए एक पैटर्न से मेल खाती है। –

+0

प्रीकंपिलिंग, यहां तक ​​कि एकल उपयोग के लिए, मेरे परीक्षण में निरंतर बेहतर रेगेक्स प्रदर्शन उत्पन्न होता है। यह एकल उपयोग के लिए बहुत कुछ नहीं है, लेकिन प्रदर्शन प्रदर्शन नहीं है। – patjbs

+0

तो आप लेआउट प्रति एक नियमित अभिव्यक्ति बनाते हैं और जब भी आपको एक अनुरूप रेखा मिलती है, तो इसका उपयोग करें, है ना? –

5

कुछ प्रदर्शन विचार:

  • (0|1)
  • के बजाय [01] का उपयोग करें
  • उपयोग गैर पर कब्जा समूहों (?:expr बजाय कब्जा समूहों की ) (यदि आप वास्तव में समूहीकरण की जरूरत है)

संपादित ऐसा लगता है के रूप में है कि अपने मूल्यों खाली स्थान के द्वारा अलग कर रहे हैं, क्यों नहीं करते क्या आप इसे वहां विभाजित करते हैं?

+0

हां, यह वास्तव में छोटे रेगेक्स के प्रति लेआउट की सूची रखने के लिए और अधिक फायदेमंद हो सकता है, और '\ t' के आधार पर स्ट्रिंग को विभाजित कर सकता है और फिर प्रत्येक से मेल खाता है। –

1

मैं सिर्फ हाथ से एक लेक्सर का निर्माण करूंगा।

इस मामले में ऐसा लगता है कि आपके पास टैब द्वारा अलग किए गए फ़ील्ड का एक गुच्छा है, जिसमें एक नई लाइन द्वारा रिकॉर्ड किया गया रिकॉर्ड है। एक्सएमएल फ़ाइल कॉलम के अनुक्रम, और उनके प्रकार का वर्णन करने के लिए प्रतीत होता है।

हाथ से प्रत्येक मामले को पहचानने के लिए कोड लिखना शायद सबसे खराब मामले में कोड की 5-10 लाइनें है।

आप फिर xml फ़ाइल से PrimitiveType [] मानों का एक arraay उत्पन्न करना चाहते हैं, और फिर नीचे "GetValues" फ़ंक्शन को कॉल करना चाहते हैं।

इससे आपको इनपुट स्ट्रीम के माध्यम से एक ही पास करने की अनुमति मिलनी चाहिए, जो रेगेक्स का उपयोग करने पर एक बड़ा बढ़ावा देना चाहिए।

आपको अपने स्वयं के "स्कैनएक्सवाईड" विधियों की आपूर्ति करने की आवश्यकता होगी। उन्हें लिखना आसान होना चाहिए। Regexes का उपयोग कर उन्हें w/बाहर लागू करना सबसे अच्छा है।

public IEnumerable<object[]> GetValues(TextReader reader, PrimitiveType[] schema) 
{ 
    while (reader.Peek() > 0) 
    { 
     var values = new object[schema.Length]; 
     for (int i = 0; i < schema.Length; ++i) 
     { 
      switch (schema[i]) 
      { 
       case PrimitiveType.BIT: 
        values[i] = ScanBit(reader); 
        break; 
       case PrimitiveType.DATE: 
        values[i] = ScanDate(reader); 
        break; 
       case PrimitiveType.FLOAT: 
        values[i] = ScanFloat(reader); 
        break; 
       case PrimitiveType.INTEGER: 
        values[i] = ScanInt(reader); 
        break; 
       case PrimitiveType.STRING: 
        values[i] = ScanString(reader); 
        break; 
      } 
     } 

     EatTabs(reader); 

     if (reader.Peek() == '\n') 
     { 
      break; 
     } 

    if (reader.Peek() == '\n') 
    { 
     reader.Read(); 
    } 
    else if (reader.Peek() >= 0) 
    { 
     throw new Exception("Extra junk detected!"); 
    } 

    yield return values; 

    } 

    reader.Read(); 
} 
संबंधित मुद्दे