2010-08-19 1 views
39

से रेखा टिप्पणियों को पट्टी करने के लिए रेगेक्स मैं कुछ सी # कोड से ब्लॉक या लाइन टिप्पणियों को स्ट्रिप करने के लिए नियमित रूप से काम कर रहा हूं। मैंने साइट पर अन्य उदाहरणों को देखा है, लेकिन मुझे सटीक उत्तर नहीं मिला है जिसे मैं ढूंढ रहा हूं।सी #

मैं RegexOptions.Singleline के साथ इस रेगुलर एक्सप्रेशन के उपयोग को पूरी तरह ब्लॉक टिप्पणियां (/ * टिप्पणी * /) से मेल कर सकते हैं:

(/\*[\w\W]*\*/)

और मैं में लाइन टिप्पणियां (// टिप्पणी) से मेल कर सकते हैं उनके संपूर्णता RegexOptions.Multiline के साथ इस रेगुलर एक्सप्रेशन के उपयोग:

(//((?!\*/).)*)(?!\*/)[^\r\n]

नोट: मैं [^\r\n] बजाय +०१२३१८५२१७० उपयोग कर रहा हूँक्योंकि $ में भी मैच में \r शामिल है।

हालांकि, यह काफी जिस तरह से मैं चाहता हूं उसे काम नहीं करता है।

यहाँ अपने परीक्षण कोड है कि मैं के खिलाफ मिलान कर रहा हूँ है:

// remove whole line comments 
bool broken = false; // remove partial line comments 
if (broken == true) 
{ 
    return "BROKEN"; 
} 
/* remove block comments 
else 
{ 
    return "FIXED"; 
} // do not remove nested comments */ bool working = !broken; 
return "NO COMMENT"; 

ब्लॉक एक्सप्रेशन से मेल खाता

/* remove block comments 
else 
{ 
    return "FIXED"; 
} // do not remove nested comments */ 

जो ठीक है और अच्छा है, लेकिन लाइन एक्सप्रेशन से मेल खाता

// remove whole line comments 
// remove partial line comments 

और

// do not remove nested comments 

इसके अलावा, अगर मैं लाइन अभिव्यक्ति में */सकारात्मक अग्रदर्शी दो बार नहीं है, यह

// do not remove nested comments * 

जो मैं वास्तव में नहीं चाहिए मेल खाता है।

क्या मैं चाहता हूँ एक अभिव्यक्ति है कि पंक्ति के अंत में वर्ण से मेल खाएगी, // के साथ शुरू, है, लेकिन नहीं// और पंक्ति के अंत के बीच */ शामिल करता है।

इसके अलावा, बस मेरी जिज्ञासा को पूरा करने के लिए, क्या कोई यह समझा सकता है कि मुझे दो बार लुकहेड क्यों चाहिए? (//((?!\*/).)*)[^\r\n] और (//(.)*)(?!\*/)[^\r\n] दोनों में *, लेकिन (//((?!\*/).)*)(?!\*/)[^\r\n] और (//((?!\*/).)*(?!\*/))[^\r\n] शामिल नहीं होंगे।

+3

क्या आपने यह मामला भी माना है जहां 'स्ट्रिंग foo = "http://stackoverflow.com;" ' –

+1

लालसा के कारण आपका'/* ... */'पैटर्न ओवरमैच, उदा। '/ * टिप्पणी 1 */एक टिप्पणी नहीं पर विचार करें!/* टिप्पणी 2 */'। – polygenelubricants

+0

आप इसके बजाय सी # के लिए एक पार्सर का उपयोग करने पर विचार कर सकते हैं: http://stackoverflow.com/questions/81406/parser-for-c – TrueWill

उत्तर

73

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

बात यह है कि हर बार आपके पास /* और // और शाब्दिक तार एक-दूसरे के साथ "हस्तक्षेप" करते हैं, यह हमेशा ऐसा होता है जो प्राथमिकता लेता है। यह बहुत सुविधाजनक है क्योंकि यह बिल्कुल नियमित अभिव्यक्ति कैसे काम करता है: पहले पहले मैच को ढूंढें।

तो चलो एक नियमित अभिव्यक्ति है कि उन चार टोकन से प्रत्येक से मेल खाता निर्दिष्ट कर सकते हैं:

var blockComments = @"/\*(.*?)\*/"; 
var lineComments = @"//(.*?)\r?\n"; 
var strings = @"""((\\[^\n]|[^""\n])*)"""; 
var verbatimStrings = @"@(""[^""]*"")+"; 

शीर्षक में प्रश्न (पट्टी टिप्पणियाँ) उत्तर देने के लिए, हम की जरूरत है:

  • ब्लॉक बदलें कुछ भी नहीं
  • लाइन टिप्पणियों को एक नई लाइन के साथ बदलें (क्योंकि रेगेक्स नई लाइन खाती है)
  • उन शाब्दिक तारों को रखें जहां वे हैं।

Regex.Replace आसानी से एक MatchEvaluator फ़ंक्शन का उपयोग कर सकते हैं:

string noComments = Regex.Replace(input, 
    blockComments + "|" + lineComments + "|" + strings + "|" + verbatimStrings, 
    me => { 
     if (me.Value.StartsWith("/*") || me.Value.StartsWith("//")) 
      return me.Value.StartsWith("//") ? Environment.NewLine : ""; 
     // Keep the literal strings 
     return me.Value; 
    }, 
    RegexOptions.Singleline); 

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

+0

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

+2

@Welton: ठीक है, आप केवल बाद में 'Regex.Replace (@ "^ (\ s * \ r? \ N) {2,}", पर्यावरण। NEWline, RegexOptions.Multiline) चला सकते हैं, लेकिन यह रिक्त डबल-लाइनों को हटा देगा जिनके पास * इसमें कोई टिप्पणी नहीं थी। – Timwi

+0

मैंने देखा कि आपने इसका परीक्षण किया: http://csharp.pastebin.com/0aqBdFE5 लेकिन जब आपके पास ऐसा कुछ है: स्ट्रिंग इनपुट = "1 + 2 // टिप्पणियां"; यह विफल रहता है यह आपको पर्यावरण के कारण "1 + 2 \ r \ n" के रूप में देता है। टर्नरी ऑपरेटर – juFo

7

इससे पहले कि आप यह लागू है, तो आप के लिए यह पहली

  1. सरल टिप्पणियों/* *///, ///
  2. मल्टी लाइन टिप्पणियों/* यह \ निस \ परीक्षण मामलों बनाने की आवश्यकता होगी na \ ntest */
  3. कोड var a = "apple" की पंक्ति के बाद टिप्पणियां; // परीक्षण या/* परीक्षण */
  4. टिप्पणियों के भीतर
  5. टिप्पणियाँ/* यह // है एक परीक्षण /या // यह/, एक परीक्षण */
  6. सरल गैर टिप्पणी है कि टिप्पणियों की तरह लग रही है और प्रतीत होता है उद्धरण में विभिन्न टिप्पणी = "/ * यह एक परीक्षण है * /", या var url = "http://stackoverflow.com"; "और/* या */और" var एबीसी = @ "इस/* \ N में बोली \ n */एक टिप्पणी है", के साथ या के बीच रिक्त स्थान के बिना
:
  • परिसर गैर टिप्पणी टिप्पणी की तरह लग रहे taht

    वहां शायद अधिक मामले हैं।

    एक बार जब आप उनमें से सभी हो जाएंगे, तो आप उनमें से प्रत्येक के लिए एक पार्सिंग नियम बना सकते हैं, या उनमें से कुछ समूह बना सकते हैं।

    अकेले नियमित अभिव्यक्ति के साथ इसे हल करना संभवतः बहुत कठिन और त्रुटि-प्रवण, परीक्षण करने में कठोर और आपके और अन्य प्रोग्रामर द्वारा बनाए रखने के लिए कठिन होगा।

  • +0

    होलीस्ट्रीम, मेरे पास आपके द्वारा वर्णित कुछ परीक्षण मामले हैं, लेकिन सभी नहीं। मेरा नमूना कवर 1 (आंशिक रूप से), 2, 3, और 4. 5 और 6 अच्छे अंक हैं जिन्हें मैंने नहीं माना था। –

    +0

    होलीस्ट्रीम, मेरा मानना ​​है कि आप इसे जितना कठिन हो उतना कठिन बना रहे हैं। दो टिप्पणी शैलियों का मिलान नियमित अभिव्यक्तियों के साथ वास्तव में आसान है - असल में, सी # (और सी ++) लेक्सर शायद ऐसा करता है। यह HTML की तरह कुछ के विपरीत है, जो regexes से मेल खाना मुश्किल है क्योंकि HTML टैग घोंसला कर सकते हैं और क्योंकि वे कई अलग-अलग किस्मों में आते हैं। – Timwi

    +0

    @Timwi: वास्तव में, .NET एक व्याख्यात्मक विश्लेषक का उपयोग करता है। टिप्पणी प्रतीक सिर्फ टोकन हैं। http: //en.wikipedia।संगठन/विकी/लेक्सिकल_एनालिसिस – chilltemp

    4

    आप की तरह एक अभिव्यक्ति के साथ कोड tokenize सकता है: (। जैसे 'foo')

    @(?:"[^"]*")+|"(?:[^"\n\\]+|\\.)*"|'(?:[^'\n\\]+|\\.)*'|//.*|/\*(?s:.*?)\*/ 
    

    यह भी कुछ ऐसी अमान्य पलायन/संरचनाओं से मेल खाएंगे, लेकिन शायद हित के सभी मान्य टोकन के अनुरूप होगा (जब तक मैं कुछ भूल गया), इस प्रकार वैध कोड के लिए अच्छी तरह से काम कर रहे हैं।

    उन हिस्सों को प्रतिस्थापित करने और कैप्चर करने में इसका उपयोग करके आप वांछित परिणाम देंगे। अर्थात:

    static string StripComments(string code) 
    { 
        var re = @"(@(?:""[^""]*"")+|""(?:[^""\n\\]+|\\.)*""|'(?:[^'\n\\]+|\\.)*')|//.*|/\*(?s:.*?)\*/"; 
        return Regex.Replace(code, re, "$1"); 
    } 
    

    Example app:

    using System; 
    using System.Text.RegularExpressions; 
    
    namespace Regex01 
    { 
        class Program 
        { 
         static string StripComments(string code) 
         { 
          var re = @"(@(?:""[^""]*"")+|""(?:[^""\n\\]+|\\.)*""|'(?:[^'\n\\]+|\\.)*')|//.*|/\*(?s:.*?)\*/"; 
          return Regex.Replace(code, re, "$1"); 
         } 
    
         static void Main(string[] args) 
         { 
          var input = "hello /* world */ oh \" '\\\" // ha/*i*/\" and // bai"; 
          Console.WriteLine(input); 
    
          var noComments = StripComments(input); 
          Console.WriteLine(noComments); 
         } 
        } 
    } 
    

    आउटपुट:

    hello /* world */ oh " '\" // ha/*i*/" and // bai 
    hello oh " '\" // ha/*i*/" and 
    
    +0

    मैं इसे आज़मा दूंगा। धन्यवाद। –

    +1

    रुको, यह पूछे जाने के बाद 2 साल का जवाब क्यों दिया गया, उत्तर दिया और स्वीकार कर लिया? व्यावहारिक रूप से एक ही जवाब दे रहा है? यह मेरी सूची पर भी कैसे दिखाया गया? कुछ बग या कुछ होना चाहिए, मैं ऐसी चीजें नहीं करता। (एलओएल) – Qtax

    +0

    मुझे पता चला कि यह मेरे लिए सही जवाब है (सी #), हालांकि रेगेक्स जावास्क्रिप्ट पर काम नहीं करता है। –

    1

    मैं http://gskinner.com/RegExr/ पर इस एक पाया (नाम "नेट टिप्पणियाँ aspx")

    (//[\t|\s|\w|\d|\.]*[\r\n|\n])|([\s|\t]*/\*[\t|\s|\w|\W|\d|\.|\r|\n]*\*/)|(\<[!%][ \r\n\t]*(--([^\-]|[\r\n]|-[^\-])*--[ \r\n\t%]*)\>) 
    

    जब मैं इसका परीक्षण करता हूं तो यह सभी // टिप्पणियों और/* टिप्पणियों को हटा देता है */जैसा कि इसे पीछे उद्धरण के अंदर छोड़ देना चाहिए।

    इसका परीक्षण नहीं किया है, लेकिन यह बहुत अच्छी तरह से काम करता है (भले ही यह रेगेक्स की एक भयानक राक्षसी रेखा है)।

    +0

    ठीक है .. कुछ परीक्षणों के बाद मैंने देखा कि इसमें कम से कम साइन (-) और एकाधिक मल्टी लाइन टिप्पणियां (/ * टिप्पणी */टिप्पणी नहीं/टिप्पणी फिर से * /) वाली टिप्पणियों में समस्याएं हैं। लेकिन अगर कोई इसे ठीक करने की परवाह करता है, तो मुझे लगता है कि यह एक बहुत अच्छा समाधान है। – einord

    +0

    मेरे लिए यह ठीक काम करता है:) – 99999

    0
    के लिए ब्लॉक टिप्पणियाँ

    (/ * ... * /) आप इस exp उपयोग कर सकते हैं:

    /\*([^\*/])*\*/

    यह भी बहु टिप्पणी के साथ काम करेंगे।

    0

    इसके अलावा सी # कोड minification के लिए अपने प्रोजेक्ट देखें: CSharp-Minifier

    टिप्पणी, रिक्त स्थान और और कोड से पंक्ति विराम के दूर करने के अलावा, वर्तमान समय में यह स्थानीय चर नाम सेक और एक अन्य minifications ऐसा करने में सक्षम है।