正则表达式环视

时间:2009-01-08 17:08:51

标签: c# .net regex

我不认为只用正则表达式就可以做到这一点,但我不是专家,所以我觉得值得问。

我正在尝试使用.NET正则表达式进行大量搜索和替换C#代码。我想要做的是找到一行代码,其中在DateTime类型的变量上调用特定函数。例如:

axRecord.set_Field("CreatedDate", m_createdDate);

我知道它是早期的一个DateTime变量b / c,代码文件就是这行:

DateTime m_createdDate;

但似乎我不能在负面的后视中使用命名组,如:

(?<=DateTime \k<1>.+?)axRecord.set_[^ ]+ (?<1>[^ )]+)

如果我尝试匹配变量声明和函数调用之间的所有文本,如下所示:

DateTime (?<1>[^;]+).+?axRecord.set.+?\k<1>

它将找到第一个匹配 - 首先基于声明的第一个变量 - 然后它找不到任何其他匹配,因为代码的布局如下:

DateTime m_First;
DateTime m_Second;
...
axRecord.set_Field("something", m_First);
axRecord.set_Field("somethingElse", m_Second);

并且第一个匹配包含第二个变量声明。

使用正则表达式有没有一种好方法可以做到这一点,还是我必须在我的逻辑中使用脚本?

5 个答案:

答案 0 :(得分:5)

看看我对这个问题的回答Get a methods contents from a C# file

它提供了指向页面的链接,这些页面显示了如何使用内置的.net语言解析器来简单可靠地执行此操作(即不是通过询问“我正在搜索的用法”,而是通过正确解析代码使用VS代码解析工具)。

我知道这不是RegEx的答案,但我认为RegEx不是答案。

答案 1 :(得分:1)

使用单个正则表达式很难做到这一点。但是,如果您考虑使用一些状态处理行,则可以执行此操作。

注意:我无法确切地告诉您在axRecord线上想要匹配的内容,因此您可能需要适当调整该正则表达式。

void Process(List<string> lines) {
  var comp = StringComparer.Ordinal;
  var map = new Hashset<string>comp);
  var declRegex = new Regex("^\s(?<type>\w+)\s*(?<name>m_\w+)\s*";);
  var toReplaceRegex = new Regex("^\s*axRecord.set_(?<toReplace>.*(?<name>m_\w+).*)");

  for( var i = 0; i < lines.Length; i++) {
    var line = lines[i];
    var match = declRegex.Match(line);
    if ( match.Success ) {
      if ( comp.Equals(match.Groups["type"], "DateTime") ) {
        map.Add(comp.Groups["name"]);
      } else {
        map.Remove(comp.Groups["name"]);
      }
      continue;
    }

    match = toReplaceRegex.Match(line);
    if ( match.Success && map.Contains(match.Groups["name"]) ) {
      // Add your replace logic here
    }
}

答案 2 :(得分:0)

使用正则表达式无法完成此操作。首先,C#的语法不规则;但更重要的是,你在谈论分析词汇无关的表达。对于这类事情,您将需要完整的语义分析。这意味着词法分析器,解析器,名称绑定和最终类型检查器。获得带注释的AST后,您可以查找所需的字段,然后阅读该类型。

我猜这是比你想做的更多的工作,因为它是一个完整的C#编译器的一半。

答案 3 :(得分:0)

这很奇怪。我设法构建了一个可以找到它的正则表达式,但它只匹配第一个。

(?<=private datetime (?<1>\b\w+\b).+?)set_field[^;]+?\k<1>

所以看起来如果我不能在lookbehind中使用命名组,我至少可以在lookbehind中建立一个命名组,并在匹配中使用它。但是看起来当它只匹配函数调用(这就是我想要的)时,插入位置被移动到那一行,因此它找不到任何新的匹配,因为它传递了它们的声明。或者我可能不明白引擎是如何工作的。

我想我正在寻找的是一个正则表达式选项,告诉它查看匹配内部以获得更多匹配。考虑到它,似乎也需要基本的html正则表达式解析。你找到一个标签,然后它是结束标签,整个页面都包含在那个匹配中,所以除非你递归地将模式应用于每个匹配,否则你将找不到任何其他标签。

任何人都对此有所了解,还是我在疯狂?

答案 4 :(得分:0)

试试这个:

@"(?s)set_Field\(""[^""]*"",\s*(?<vname>\w+)(?<=\bDateTime\s+\k<vname>\b.+)"

首先执行lookbehind,强制正则表达式按特定顺序搜索方法调用:声明变量的顺序。你想要做的是首先匹配一个看起来很可靠的方法调用,然后使用lookbehind来验证变量的类型。

我只是粗略猜测了与方法调用匹配的部分。就像其他人所说的那样,无论你使用哪种正则表达式都必须根据你的代码量身定制;没有通用的解决方案。