【问题标题】:Finding methods in source code using regular expressions使用正则表达式在源代码中查找方法
【发布时间】:2009-04-07 17:26:45
【问题描述】:

我有一个程序,它查看源代码,定位方法,并对每个方法内部的代码执行一些计算。我正在尝试使用正则表达式来执行此操作,但这是我第一次在 C# 中使用它们,我在测试结果时遇到了困难。

如果我使用这个正则表达式来查找方法签名:

((private)|(public)|(sealed)|(protected)|(virtual)|(internal))+([a-z]|[A-Z]|[0-9]|[\s])*([\()([a-z]|[A-Z]|[0-9]|[\s])*([\)|\{]+)

然后通过这种方法拆分源代码,将结果存储在字符串数组中:

string[] MethodSignatureCollection = regularExpression.Split(SourceAsString);

这会让我得到我想要的,即包含其中代码的方法列表吗?

【问题讨论】:

    标签: c# regex


    【解决方案1】:

    我强烈建议使用Reflection(如果合适的话)或CSharpCodeProvider.Parse(...)(rstevens 推荐)

    编写一个适用于所有情况的正则表达式可能非常困难。

    以下是您必须处理的一些情况:

    public /* comment */ void Foo(...)      // Comments can be everywhere
    string foo = "public void Foo(...){}";  // Don't match signatures in strings 
    private __fooClass _Foo()               // Underscores are ugly, but legal
    private void @while()                   // Identifier escaping
    public override void Foo(...)           // Have to recognize overrides
    void Foo();                             // Defaults to private
    void IDisposable.Dispose()              // Explicit implementation
    
    public // More comments                 // Signatures can span lines
        void Foo(...)
    
    private void                            // Attributes
       Foo([Description("Foo")] string foo) 
    
    #if(DEBUG)                              // Don't forget the pre-processor
        private
    #else
        public
    #endif
        int Foo() { }
    

    注意事项:

    • Split 方法会丢弃它匹配的所有内容,因此您实际上会丢失所有要拆分的“签名”。
    • 不要忘记签名中可以包含逗号
    • {...} 可以嵌套,您当前的正则表达式可能会消耗更多的{
    • 还有很多其他的东西(预处理器命令、using 语句、属性、cmets、enum 定义、属性)可以显示在代码中,所以仅仅因为某些东西位于两个方法签名之间并不能实现方法体的一部分。

    【讨论】:

      【解决方案2】:

      也许使用 CSharpCodeProvider.Parse() 可以将 C# 源代码“编译”成 CompileUnit 是一种更好的方法。 然后,您可以浏览该编译单元中的命名空间、类型、类和方法。

      【讨论】:

        【解决方案3】:

        使用ICSharpCode.NRefactory.CSharp;

        PM> 安装包 ICSharpCode.NRefactory

        var parser = new CSharpParser();
        var syntaxTree = parser.Parse(File.ReadAllText(sourceFilePath));
        
        var result = syntaxTree.Descendants.OfType<MethodDeclaration>()
            .FirstOrDefault(y => y.NameToken.Name == methodName);
        if (result != null)
        {
            return result.ToString(FormattingOptionsFactory.CreateSharpDevelop()).Trim();
        }
        

        【讨论】:

          【解决方案4】:

          我想,使用正则表达式来获得一些东西是可行的,但这确实需要非常仔细地查看 C# 语言的规范并深入了解 C# 语法,这不是一个简单的问题。我知道你说过你想将方法存储为字符串数组,但大概还有其他的东西。已经指出要考虑使用反射,但是如果这不能满足您的要求,则应考虑使用 ANTLR(另一种语言识别工具)。 ANTLR 确实有可用的 C# 语法。

          http://www.antlr.org/about.html

          【讨论】:

          • 其实普通的正则表达式是不能解决这个问题的,因为不能算。 (不过,Perl “正则表达式”是图灵完备的。)
          【解决方案5】:

          不,这些访问修饰符也可以用于内部类和字段等。您需要编写一个完整的 C# 解析器才能使其正确。

          你可以使用反射做你想做的事。尝试以下操作:

            var methods = typeof (Foo).GetMethods();
            foreach (var info in methods)
            {
              var body = info.GetMethodBody();
            }
          

          这可能有您计算所需的内容。

          如果您需要原始 C# 源代码,则无法通过反射获得它。不要编写自己的解析器。使用现有的here

          【讨论】:

            猜你喜欢
            • 1970-01-01
            • 2019-01-17
            • 1970-01-01
            • 2014-05-13
            • 1970-01-01
            • 1970-01-01
            • 2013-08-14
            • 2016-07-15
            • 2013-07-02
            相关资源
            最近更新 更多