开发者

Parsing #regions within Code Files

开发者 https://www.devze.com 2023-02-06 16:29 出处:网络
I\'m trying to create a C# program that extracts the code contained within #region tags in *.cs files.I more or less just want to be able to anotat开发者_StackOverflow社区e the code I\'m working on an

I'm trying to create a C# program that extracts the code contained within #region tags in *.cs files. I more or less just want to be able to anotat开发者_StackOverflow社区e the code I'm working on and have it be accessible to this other program as just text.

Is there something that already exists that accomplishes this?

Say I have code like this:

#region ClassName.Test()
public static void Test()
{
     //Some method that does stuff
}
#endregion

I'd like to be able to extract

public static void Test()
{
     //Some method that does stuff
}

from the *.cs as a string when I specify that I'm looking for Class.Test().


If you are not worried about nested #regions. This code would do the trick. Call GetCodeRegions() passing in your code string (you obtained by using File.ReadAlltext) to get a list of the code snippets within the regions you want.

    static void Main(string[] args)
    {
        var code = @"#region ClassName.Test()    //Some method that does stuff
            //some stuff
            #endregion

            #region ClassCName.Random()
            public static void Test()
            {
                 //Some more stuff
            }
            #endregion";

        List<string> codeRegions = GetCodeRegions(code);
    }

    private static List<string> GetCodeRegions(string code)
    {
        List<string> codeRegions = new List<string>();

        //Split code into regions
        var matches = Regex.Matches(code, "#region.*?#endregion", RegexOptions.Singleline);

        foreach (var match in matches)
        {
            //split regions into lines
            string[] lines = match.ToString().Split(new string[] { "\r\n" }, StringSplitOptions.None);

            if (lines.Length > 2)
            {
                codeRegions.Add(string.Join("\r\n", lines, 1, lines.Length - 2));
            }

        }

        return codeRegions;
    }


If you don't mind potential troublesome issues then you can simply open the file and search for the keywords you are looking for.

The problem comes from that fact that strings may contain the information you are looking for but are not meant to be searched. You can attempt to ignore strings but this can get a little complicated because of all the ways " is used (\", "", etc...).

If you can safely ignore strings in C# then simply open the text file, search line by line what you are looking for(string.Find).

If your looking to do it right then using CodeDOM is the way to go!


Lets say we have the whole code in a string classcode

we can do this

string[] regions =Regex.Split("#region",classcode);

now the region string array will consist of your region codes which you can access as you access arrays.

you will have to remove the region name and #endregion from the individual strings in array which is not so troublesome


I'd like to improve on the answers provided so far. Why? None of them would easily allow the developer to identify the region from which a code snippet comes from. To be fair, I've prepared a code that compares the three solutions provided so far. My test also proves that the solution provided by https://stackoverflow.com/users/418281/ankush-roy should not be used as it can also return code that do not belong to a region.

First the results:---------

//****** Result:: Regex.Split(code, "#region")  
public class TestRegionParsing
{
    private void Test1()
    {
        //this code should not be read
    }
     ClassName.Test()    
    //Some method that does stuff
    //some stuff
    #endregion ClassName.Test()
     ClassCName.Random()
    public static void Test()
    {
         //Some more stuff
    }
    #endregion ClassCName.Random()
    private void Test2()
    {
        //this code should not be read
    }
     ClassCName.Random()
    public static void Test3()
    {
         //Some more stuff
    }
    #endregion
}
//****** Result:: GetCodeRegions(code)
//Some method that does stuff
//some stuff
    public static void Test()
{
     //Some more stuff
}
    public static void Test3()
{
     //Some more stuff
}
//****** Result:: Utils.GetRegionsFromCShapFile(csharpFinePath)
Region name converted:1.cs 
    //Some method that does stuff
    //some stuff
Region name converted:2.cs 
    public static void Test()
    {
         //Some more stuff
    }
Region name converted:3.cs 
    public static void Test3()
    {
         //Some more stuff
    }

The CS file that was parsed by both codes:

    public class TestRegionParsing
{
    private void Test1()
    {
        //this code should not be read
    }

    #region ClassName.Test()    
    //Some method that does stuff
    //some stuff
    #endregion ClassName.Test()

    #region ClassCName.Random()
    public static void Test()
    {
         //Some more stuff
    }
    #endregion ClassCName.Random()

    private void Test2()
    {
        //this code should not be read
    }

    #region ClassCName.Random()
    public static void Test3()
    {
         //Some more stuff
    }
    #endregion
}

Now the code I've implemented

/// <summary>
    /// For a given source code, it parses all regions and creates a dictionary where 
    /// Key=region name and Value=list of region's code lines.<para />
    /// Known Issue: This method dos not work with regions within regions. <para />
    /// </summary>
    /// <param name="sourceCodeFileName">string - full source code .cs path</param>
    /// <returns>Key=region name and Value=list of region's code lines.</returns>
    public static Dictionary<string, List<string>> GetRegionsFromCShapFile(string sourceCodeFileName)
    {
        FileInfo f = new FileInfo(sourceCodeFileName);
        if (f.Length > ONE_Gb)
        {
            throw new ArgumentOutOfRangeException(string.Format("File:{0} has size greater than {1}{2}", MAX_STORAGE, STORAGE_UNIT));
        }
        Dictionary<string, List<String>> regions = new Dictionary<string, List<string>>();
        string[] readLines = File.ReadAllLines(sourceCodeFileName);
        List<string> current_list = null;

        foreach (string l in readLines)
        {
            if (l != null)
            {
                if (l.TrimStart().StartsWith("#region", StringComparison.CurrentCultureIgnoreCase))
                {
                    string key = string.Format("{0}.cs", ExtractNumber(l.Trim()));
                    if (regions.ContainsKey(key))
                    {
                        throw new ArgumentException(string.Format("Duplicate named regions detected: {0}", l.Trim()));
                    }
                    regions[key] = new List<string>();
                    current_list = regions[key];
                }
                else
                {
                    if (current_list != null) //ignores code read if it is not within a region
                    {
                        if (l.TrimStart().StartsWith("#endregion", StringComparison.CurrentCultureIgnoreCase))
                        {
                            current_list = null; //stops using the current list
                        }
                        else
                        {
                            //use current list
                            current_list.Add(l);
                        }
                    }
                }
            }
        }

        return regions;
    }

I hope that this may help.

0

精彩评论

暂无评论...
验证码 换一张
取 消