2013-08-02 5 views
7

मेरे पास एक कोड उदाहरण है जहां फ़ोरैच के साथ इसका उपयोग करने का प्रयास करते समय एक मैचकोलेक्शन प्रोग्राम को लटका लगता है।क्या एक मैच कोलेक्शन इसे फिर से चलाने की कोशिश करते समय प्रोग्राम को लटका सकता है?

मैं एक वर्ग CSSParser का उपयोग कर सीएसएस को पार्स कर रहा हूँ:

using System; 
using System.Collections.Generic; 
using System.Linq; 
using System.Text.RegularExpressions; 
using Helpers.Extensions; 

namespace Helpers.Utils 
{ 
    public class CSSParser 
    { 
     private readonly Dictionary<string, Dictionary<string, string>> 
      _dict = new Dictionary<string, Dictionary<string, string>>(); 

     private const string SelectorKey = "selector"; 
     private const string NameKey = "name"; 
     private const string ValueKey = "value"; 

     private const string GroupsPattern 
      = @"(?<selector>(?:(?:[^,{]+)\s*,?\s*)+)\{(?:(?<name>[^}:]+)\s*:\s*(?<value>[^};]+);?\s*)*\}"; 

     private const string CommentsPattern 
      = @"(?<!"")\/\*.+?\*\/(?!"")"; 

     private readonly Regex _pattern 
      = new Regex(GroupsPattern, RegexOptions.IgnoreCase | RegexOptions.Multiline); 

     public CSSParser(string cssString) 
     { 
      var noCommentsString = Regex.Replace(cssString, CommentsPattern, ""); 
      var matches = _pattern.Matches(noCommentsString); 

      foreach (Match item in matches) 
      { 
       var selector = item.Groups[SelectorKey].Captures[0].Value.Trim(); 

       var selectorParts = selector.Split(',').Select(s=>s.Trim()); 
       foreach(var part in selectorParts) 
       { 
        if (!_dict.ContainsKey(part)) 
         _dict[part] = new Dictionary<string, string>(); 
       } 

       var classNameCaptures = item.Groups[NameKey].Captures; 
       var valueCaptures = item.Groups[ValueKey].Captures; 

       var count = item.Groups[NameKey].Captures.Count; 

       for (var i = 0; i < count; i++) 
       { 
        var className = classNameCaptures[i].Value.TrimIfNotNull(); 
        var value = valueCaptures[i].Value.TrimIfNotNull(); 

        foreach(var part in selectorParts) 
        { 
         _dict[part][className] = value; 
        } 
       } 
      } 
     } 

     public IEnumerable<KeyValuePair<string,string>> LookupValues(string selector) 
     { 
      IEnumerable<KeyValuePair<string,string>> result 
       = new KeyValuePair<string,string>[]{}; 
      if (_dict.ContainsKey(selector)) 
      { 
       var subdict = _dict[selector]; 

       result = subdict.ToList(); 
      } 

      return result; 
     } 

     public string LookupValue(string selector, string style) 
     { 
      string result = null; 
      if (_dict.ContainsKey(selector)) 
      { 
       var subdict = _dict[selector]; 

       if (subdict.ContainsKey(style)) 
        result = subdict[style]; 
      } 

      return result; 
     } 
    } 
} 

और इसे इस तरह इनपुट के साथ ठीक काम करता है:

 [TestMethod] 
     public void TestParseMultipleElementNames() 
     { 
      const string css = @"h1, h2, h3, h4, h5, h6 
{ 
    font-family: Georgia, 'Times New Roman', serif; 
    color: #006633; 
    line-height: 1.2em; 
    font-weight: normal; 
} 
"; 

      var parser = new CSSParser(css); 

      Assert.AreEqual("normal", parser.LookupValue("h4", "font-weight")); 
     } 

लेकिन जब मैं यह एक सीएसएस स्ट्रिंग कोई विशेषताओं वाली के साथ चलाएँ:

 [TestMethod] 
     public void TestParseNoAttributesStyle() 
     { 
      const string css = @" 
#submenu-container 
{ 
} 
"; 

      var parser = new CSSParser(css); 

      Assert.IsFalse(parser.LookupValues("#submenu-container").Any()); 
     } 

प्रोग्राम CSSParser में इस पंक्ति पर लटक रहा है:

foreach (Match item in matches) 

डीबगर वर्तमान में निष्पादित लाइन को चिह्नित करने से रोकता है, लूप ब्लॉक स्वयं कभी नहीं पहुंचता है।

MatchCollection मेरे प्रोग्राम को क्यों लटक रहा है?

पूर्णता के लिए:

namespace Helpers.Extensions 
{ 
    public static class StringExtension 
    { 
    public static string TrimIfNotNull(this string input) 
    { 
     return input != null ? input.Trim() : null; 
    } 
    } 
} 
+2

मैं रेगेक्स के साथ कोई विशेषज्ञ नहीं हूं लेकिन रेगेक्स इंजन फंस सकता है या लंबे समय तक ले सकता है अगर उसे निरंतर लुकहेड करना है और ऑपरेशन देखना है। इन्हें कम करने के लिए अपने रेगेक्स को डिजाइन करने में मदद मिलेगी। शायद एक रेगेक्स विशेषज्ञ आपको विशिष्टताओं के साथ मदद कर सकता है। +1 =] – Sean

+1

डीबगर को रोकें और यह निर्धारित करने के लिए स्टैक को देखें कि क्या हो रहा है।सब कुछ देखने के लिए "बाहरी कोड दिखाएं" की जांच करें। – usr

+1

ए) इस तरह की भाषाओं को * वास्तव में * Regex के साथ पार्स नहीं किया जाना चाहिए। बी) क्यों नहीं [कुछ ऑफ-द-शेल्फ का उपयोग करें] (http://stackoverflow.com/q/512720/50776)? यह शायद बहुत तेज़ और अधिक मजबूत होगा और आपको अपने प्रोजेक्ट में इसे हाथ से करने से ज्यादा आगे बढ़ाएगा। – casperOne

उत्तर

1

आपका Regex बस अक्षम और जल सीपीयू है। आप इसकी पुष्टि कर सकते हैं ए) इस्तेमाल किए गए CPU समय को देखते हुए और बी) डीबगर को बार-बार रोकना और स्टैक को देखना (रेगेक्स इंजन के आंतों में होगा)।

private const string GroupsPattern 
    = @"(?<selector>(?:(?:[^,{]+)\s*,?\s*)+)\{(?:(?<name>[^}:]+)\s*:\s*(?<value>[^};]+);?\s*)*\}"; 

लिए:

+0

फिर केवल खाली सीएसएस ब्लॉक क्यों पार्स करना मुश्किल है? –

+1

मुझे नहीं पता। रेगेक्स को ठीक करना सवाल का हिस्सा नहीं है। सवाल यह है कि "एक मैचकोलेक्शन लटका सकता है"। उत्तर: नहीं, बस धीमा। – usr

+1

इसलिए, आप उत्तर –

0

मैं से regexp बदल

private const string GroupsPattern 
    = @"(?<selector>(?:(?:[^,{]+)\s*,?\s*)+)\{\s*(?:(?<name>[^}:\s]+)\s*:\s*(?<value>[^};]+);?\s*)*\}"; 

और निष्पादन समय 1 एमएस करने के लिए 22 सेकंड से नीचे चला गया।

+1

पहला regexp मूल पोस्ट जैसा नहीं है - नाम समूह में एक '\ s' अतिरिक्त है। नया रेगेक्स मूल के मुकाबले अलग-अलग परिणाम भी देगा। इसके मज़े के लिए आप इसे निम्नलिखित पाठ (एक अतिरिक्त स्थान डाला गया है) के साथ भी कोशिश कर सकते हैं। एच 1, एच 2, एच 3, एच 4, एच 5, एच 6 {फ़ॉन्ट-एफ मिली: जॉर्जिया, 'टाइम्स न्यू रोमन', सेरिफ़ ; रंग: # 006633; लाइन-ऊंचाई: 1.2em; फ़ॉन्ट-वज़न: सामान्य; } ' – Ykok

+0

धन्यवाद, मैंने पोस्ट संपादित किया ताकि यह सही जानकारी दिखा सके! मेरे पास विशेषता नामों में रिक्त स्थान नहीं होंगे। –

1

जहाँ तक मैं कह सकता हूं .net एक शाश्वत पाश में जाता है क्योंकि यह आपके द्वारा प्राप्त किए गए रेगेक्स के साथ अलग-अलग दृष्टिकोणों की कोशिश करता है (समूह पैटर्न एक) - मेरा मानना ​​है कि यह कहीं गलती करता है। मैंने इस रेगेक्स पर एक नज़र डाली है और जहां तक ​​मैं कह सकता हूं कि आप आसानी से \s* में से दो को हटा सकते हैं, अर्थात् जो नकारात्मक क्रम से पहले [^,{]+ और [^}:]+ से पहले आते हैं, क्योंकि वे पहले से ही रिक्त स्थान पर कब्जा कर लेते हैं।

तो वह है, बजाय:

private const string GroupsPattern = @"(?<selector>(?:(?:[^,{]+)\s*,?\s*)+)\{(?:(?<name>[^}:]+)\s*:\s*(?<value>[^};]+);?\s*)*\}"; 

मैं होगा:

private const string GroupsPattern = @"(?<selector>(?:(?:[^,{]+),?\s*)+)\{(?:(?<name>[^}:]+):\s*(?<value>[^};]+);?\s*)*\}"; 

अब इस regex भाव है, इसलिए मुझे की संभावना की अनदेखी हो रही है कुछ नहीं बल्कि बड़े हैं। इसके अलावा मेरा मानना ​​है कि इसके नामित कैप्चर समूहों में से कुछ में शायद अतिरिक्त रिक्त स्थान भी हैं (लेकिन ऐसा लगता है कि आप उन्हें वैसे भी ट्रिम करते हैं)।

आशा है कि यह उपयोग योग्य है। हालांकि इसमें अभी भी कुछ समय लगता है, यह आपके द्वारा दिए गए उदाहरण के साथ काम करता है।

+0

regexp matcher केवल धीमा, कोई शाश्वत loops थे। जब मैंने कुछ संशोधन किए थे, तो cssparser एक आंखों की झपकी में 10k सीएसएस फ़ाइल को पार्स कर सकता है जो मेरी आवश्यकताओं के लिए पर्याप्त है। मैं आपके regexp का उपयोग करने पर विचार करेंगे। –

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

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