使用正则表达式在源代码中查找方法

使用正则表达式在源代码中查找方法

问题描述:

我有一个程序在源代码中查找,查找方法并对每个方法内部的代码执行一些计算。我试图使用正则表达式来做到这一点,但这是我第一次在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); 

将这让我得到我想要的东西,即方法列表,包括其中的代码?

我会强烈建议使用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陈述,性能更{ ,评论,enum定义,属性),可以在代码中显示,所以只是因为两个方法签名之间的东西不会使它成为方法体的一部分。

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

你可以用反射来做你想做的。请尝试如下所示:

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

这可能是您计算所需的。

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

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

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

+0

其实,普通的正则表达式解决不了这个问题,因为他们可以不计。 (尽管Perl是“正则表达式”,但Turing是完整的。) – RossFabricant 2009-04-07 17:56:20

也许这是一个较好的方法为使用CSharpCodeProvider.Parse(),它可以“编译” C#源代码转换成一个CompileUnit。 然后,您可以遍历该编译单元中的命名空间,类型,类和方法。

+0

对于CSharpCodeProvider – 2009-04-07 18:14:39

使用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(); 
}