我不认为只用正则表达式就可以做到这一点,但我不是专家,所以我觉得值得问。
我正在尝试使用.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);
并且第一个匹配包含第二个变量声明。
使用正则表达式有没有一种好方法可以做到这一点,还是我必须在我的逻辑中使用脚本?
答案 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来验证变量的类型。
我只是粗略猜测了与方法调用匹配的部分。就像其他人所说的那样,无论你使用哪种正则表达式都必须根据你的代码量身定制;没有通用的解决方案。