2013-05-23 2 views
5

में संग्रहीत कोड की अनदेखी लाइनों के कुशल तरीका मेरे पास string[] है जिसमें कोड शामिल है। प्रत्येक पंक्ति में कुछ प्रमुख रिक्त स्थान होते हैं। मुझे मौजूदा प्रारूपण को बदलने के बिना जितना संभव हो सके कोड को 'अनइंडेंट' करने की आवश्यकता है।एक स्ट्रिंग

उदाहरण के लिए की सामग्री को मेरी string[] हो सकता है

           public class MyClass 
             { 
              private bool MyMethod(string s) 
              { 
               return s == ""; 
              } 
             } 

मैं एक यथोचित सुरुचिपूर्ण और कुशल पद्धति प्राप्त करना चाहते हैं (LINQ?) यह

public class MyClass 
{ 
    private bool MyMethod(string s) 
    { 
     return s == ""; 
    } 
}

को बदलने के लिए स्पष्ट रूप से कहें मैं

IEnumerable<string> UnindentAsMuchAsPossible(string[] content) 
{ 
    return ???; 
} 
+0

आप यकीन है कि यह सभी रिक्त स्थान है कर रहे हैं शामिल है, और कोई टैब नहीं? – Servy

+2

आप 'UnindentAsMuchAs संभावित' को 'शून्य' वापस करने के लिए नहीं चाहते हैं, है ना? –

+0

आप सही @Tim हैं। फिक्स्ड। – shamp00

उत्तर

3

टिम Schmelter के जवाब पर निर्माण:

static IEnumerable<string> UnindentAsMuchAsPossible(IEnumerable<string> input) 
{ 
    const int TabWidth = 4; 

    if (!input.Any()) 
    { 
     return Enumerable.Empty<string>(); 
    } 

    int minDistance = input 
     .Where(line => line.Length > 0) 
     .Min(line => line 
      .TakeWhile(Char.IsWhiteSpace) 
      .Sum(c => c == '\t' ? TabWidth : 1)); 

    return input 
     .Select(line => line.Replace("\t", new string(' ', TabWidth))) 
     .Select(line => line.Substring(Math.Min(l.Length, minDistance)); 
} 

यह संभालता है:

  • टैब वर्ण
  • स्रोत कोड है कि खाली लाइनों
+0

मेरे उपयोग के मामले में दोनों टैब और खाली लाइनें बदलती हैं। यह जवाब अतिरिक्त मील जाता है। – shamp00

1

यह पहली बार न्यूनतम पहचान पायेगा और फिर थै को हटा देगा प्रत्येक पंक्ति के लिए रिक्त स्थान की संख्या।

var code = new [] { " foo", " bar" }; 

var minIndent = code.Select(line => line.TakeWhile(ch => ch == ' ').Count()).Min(); 
var formatted = code.Select(line => line.Remove(0, minIndent)); 

यह एक ही अभिव्यक्ति में सब कुछ लिखने के लिए संभव हो जाएगा, लेकिन मुझे लगता है कि minIndent चर कोड अधिक पठनीय बनाता है, जबकि यह अधिक कार्यात्मक सुरुचिपूर्ण है।

3

बस पहली पंक्ति पर प्रमुख स्थानों की संख्या गिनती, और फिर प्रत्येक पंक्ति की शुरुआत से "निकालें" कि सारे वर्ण:

IEnumerable<string> UnindentAsMuchAsPossible(string[] content) 
{ 
    int spacesOnFirstLine = content[0].TakeWhile(c => c == ' ').Count(); 
    return content.Select(line => line.Substring(spacesOnFirstLine)); 
} 
+1

यह मानता है कि पहली पंक्ति कम से कम इंडेंट है (जो मामला नहीं हो सकता है)। –

+0

@MattHouser यदि कार्यक्रम शुरू करने के लिए ठीक से स्वरूपित किया गया है तो यह मामला कैसे हो सकता है? क्या आपके पास ऐसे कार्यक्रम का उदाहरण है? – Servy

+0

जहां मूल प्रश्न में यह कहा गया है कि स्रोत कोड ठीक से स्वरूपित करने के लिए स्वरूपित है? प्रश्न केवल इतना कहता है कि मौजूदा स्वरूपण को बनाए रखा जाना है। –

2

एक छोटे से LINQ और regex का उपयोग कम से कम खरोज लगता है, फिर सभी पंक्तियों से वर्णों की संख्या हटा दें।

string[] l_lines = { 
         "           public class MyClass", 
         "           {", 
         "            private bool MyMethod(string s)", 
         "            {", 
         "             return s == \"\";", 
         "            }", 
         "           }" 
        }; 

int l_smallestIndentation = 
    l_lines.Min(s => Regex.Match(s, "^\\s*").Value.Length); 

string[] l_result = 
    l_lines.Select(s => s.Substring(l_smallestIndentation)) 
      .ToArray(); 

foreach (string l_line in l_result) 
    Console.WriteLine(l_line); 

प्रिंटों:

public class MyClass 
{ 
    private bool MyMethod(string s) 
    { 
     return s == ""; 
    } 
} 

इस कार्यक्रम सरणी में सभी स्ट्रिंग्स को स्कैन करेगा। आप यह मान सकते हैं कि पहली पंक्ति से कम दांतेदार है, तो आप केवल पहली पंक्ति को स्कैन करके प्रदर्शन में सुधार कर सकते हैं:

int l_smallestIndentation = 
    Regex.Match(l_lines[0], "^\\s*").Value.Length; 

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

टैब पर अतिरिक्त वजन देने के लिए ऊपर दिए गए कोड को संशोधित करना भी संभव होगा। उस बिंदु पर, रेगेक्स अब अधिक उपयोग नहीं है।

public class MyClass 
{ 
     private bool MyMethod(string s) 
     { 
       return s == ""; 
     } 
} 

आप किनारे मामले के परिदृश्यों के साथ काम करने के लिए इस कोड को संशोधित करने की आवश्यकता हो सकती है, जैसे शून्य:

string[] l_lines = { 
     "\t\t\tpublic class MyClass", 
     "      {", 
     "        private bool MyMethod(string s)", 
     "        {", 
     "  \t  \t\treturn s == \"\";", 
     "        }", 
     "\t\t\t}" 
    }; 

int l_tabWeight = 8; 
int l_smallestIndentation = 
    l_lines.Min 
    (
     s => s.ToCharArray() 
       .TakeWhile(c => Char.IsWhiteSpace(c)) 
       .Select(c => c == '\t' ? l_tabWeight : 1) 
       .Sum() 
    ); 

string[] l_result = 
    l_lines.Select 
    (
     s => 
     { 
      int l_whitespaceToRemove = l_smallestIndentation; 
      while (l_whitespaceToRemove > 0) 
      { 
       l_whitespaceToRemove -= s[0] == '\t' ? l_tabWeight : 1; 
       s = s.Substring(1); 
      } 
      return s; 
     } 
    ).ToArray(); 

प्रिंटों (अपने कंसोल विंडो संभालने मेरे जैसे एक टैब 8 की चौड़ाई है) लंबाई रेखाएं या रेखाएं जिनमें केवल सफेद जगहें होती हैं।

3

यह काम करना चाहिए:

static IEnumerable<string> UnindentAsMuchAsPossible(IEnumerable<string> input) 
{ 
    int minDistance = input.Min(l => l.TakeWhile(Char.IsWhiteSpace).Count()); 
    return input.Select(l => l.Substring(minDistance)); 
} 

यह बाईं ओर कोड चलता है, रिक्त स्थान की एक ही नंबर के साथ सभी लाइनों।

उदाहरण के लिए:

string testString = @"  
        public class MyClass 
        { 
         private bool MyMethod(string s) 
         { 
          return s == ""; 
         } 
        }"; 


string[] lines = testString.Split(new[] { Environment.NewLine }, StringSplitOptions.None); 
string[] unindentedArray = UnindentAsMuchAsPossible(lines).ToArray(); 
+2

बिल्कुल मैं क्या सोच रहा था। ओपी क्या चाहता है, इस पर निर्भर करते हुए, आप इसे बदलकर इस पर भी सुधार कर सकते हैं: 'l.TakeWhile (Char.IsWhiteSpace) .उंट()' इस पर: 'l.TakeWhile (Char.IsWhiteSpace) .Sum (c => c == '\ t'? टैबविड्थ: 1) 'जहां' टैबविड्थ '4 की तरह कुछ है। –

+1

रिक्त लाइनों को संभालने के लिए एक और सुधार होगा। आम तौर पर यदि कोई कोड लिखता है जिसमें खाली रेखा होती है, तो खाली रेखा में "\ r \ n" के अलावा कुछ भी नहीं होता है। यह कोड उस संभाल नहीं करेगा। –

1

अपने वांछित विधि इंटरफ़ेस से मेल करने के लिए:

IEnumerable<string> UnindentAsMuchAsPossible(string[] content) 
{ 
    int minIndent = content.Select(s => s.TakeWhile(c => c == ' ').Count()).Min(); 
    return content.Select(s => s.Substring(minIndent)).AsEnumerable(); 
} 

यह सभी लाइनों की न्यूनतम मांगपत्र (रिक्त स्थानों केवल, कोई टैब ग्रहण), तो से minIndent रिक्त स्थान स्ट्रिप्स हो जाता है प्रत्येक पंक्ति की शुरुआत और IEnumerable के रूप में लौटाता है।