[英]regular expression lookaround
我认为仅使用正则表达式是不可能的,但是我不是专家,所以我认为值得一问。
我正在尝试使用.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);
第一个匹配项包含第二个变量声明。
是否有一种仅使用正则表达式执行此操作的好方法,还是我必须在逻辑上求助于脚本?
看看我对这个问题的回答从C#文件中获取方法内容
它提供了指向页面的链接,这些页面显示了如何使用内置的.net语言解析器来简单,可靠地执行此操作(即,不是通过询问“我正在寻找的用法”,而是通过使用VS代码正确地解析了代码)解析工具)。
我知道这不是RegEx的答案,但我不认为RegEx是答案。
使用单个正则表达式很难做到这一点。 但是,如果您考虑对状态稍有处理的行,则可以这样做。
注意:我无法在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
}
}
这不能使用正则表达式来完成。 一方面,C#的语法不规则。 但更重要的是,您正在谈论分析在词汇上不相关的表达式。 对于这种事情,您将需要完整的语义分析。 这意味着词法分析器,解析器,名称绑定以及最后的类型检查器。 获得带注释的AST之后,您可以查找所需的字段,然后直接读取类型。
我猜这比您想做的工作要多得多,因为它大约是成熟的C#编译器的一半。
真奇怪 我设法建立了一个确实找到它的正则表达式,但它仅与第一个匹配。
(?<=private datetime (?<1>\b\w+\b).+?)set_field[^;]+?\k<1>
因此,如果我不能在后备条件中使用命名组,则至少可以在后备条件中建立命名组,并在比赛中使用它。 但是然后看起来像当它仅与函数调用(这就是我想要的)匹配时,插入号位置已移动到该行,因此它找不到任何新匹配项,因为它已传递了它们的声明。 也许我不明白引擎是如何工作的。
我猜我正在寻找的是一个正则表达式选项,它告诉它在匹配项中查找更多匹配项。 想到这一点,似乎也需要基本的html regex解析。 您找到一个标签,然后将其作为结束标签,并且整个页面都包含在该匹配项中,因此除非您递归地将模式应用于每个匹配项,否则您将找不到其他任何标签。
任何人对此一无所知,或者我在疯吗?
尝试这个:
@"(?s)set_Field\(""[^""]*"",\s*(?<vname>\w+)(?<=\bDateTime\s+\k<vname>\b.+)"
通过先进行后向查找,您将强制正则表达式按特定顺序搜索方法调用:变量声明的顺序。 您想要做的是先匹配一个看起来很可能的方法调用,然后使用后向验证变量的类型。
我只是对与方法调用匹配的部分进行了粗略的猜测。 就像其他人所说的那样,无论您使用什么正则表达式都必须根据您的代码量身定制; 没有通用的解决方案。
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.