中的模式@Jeff Wurz 的评论 https://stackoverflow.com/questions/22044801/regex-to-capture-vba-comments?lq=1#comment33424910_22044801 (^\'[^\r\n]+$|''[^\r\n]+$
) 甚至不匹配any你的测试样本,链接的问题是无用的,那里的正则表达式只会匹配OP问题中的具体评论,而不是“VBA 注释语法”。
您提出的正则表达式比我放弃正则表达式方法时的效果更好。
做得好!
问题是您无法使用正则表达式解析 VBA 注释。
In 词法分析器与解析器 https://stackoverflow.com/q/2842809/1188513, @SasQ 的回答 https://stackoverflow.com/a/3614928/1188513很好地解释了乔姆斯基的语法级别:
第三级:常规语法
他们使用常用表达,也就是说,它们只能由
字母表符号 (a,b),它们的串联 (ab,aba,bbb 等),或
替代方案(例如 a|b)。它们可以实现为有限状态
自动机 (FSA),如 NFA(非确定性有限自动机)或更好
DFA(确定性有限自动机)。常规语法无法处理
使用嵌套语法,例如正确嵌套/匹配的括号
(()()(()()))、嵌套 HTML/BBcode 标签、嵌套块等。这是因为
处理它的状态自动机应该有无限多个
状态来处理无限多个嵌套级别。
第 2 级:上下文无关语法
他们可以有语法中的嵌套、递归、自相似分支
树,因此它们可以很好地处理嵌套结构。他们可以
实现为带有堆栈的状态自动机。该堆栈用于
表示语法的嵌套级别。在实践中,他们是
通常作为自上而下的递归下降解析器实现,它使用
机器的过程调用堆栈来跟踪嵌套级别,并使用
为每个非终结符递归调用过程/函数
在他们的语法中。但他们无法处理上下文相关的
句法。例如。当你有一个表达式 x+3 并且在一个上下文中这个 x
可以是变量的名称,在其他上下文中它可以是名称
的函数等
第一级:上下文相关语法
正则表达式根本不是解决这个问题的合适工具,因为只要有多个单引号(/撇号),或者涉及双引号,您就需要确定代码行中最左边的撇号是否是在双引号内,如果是,那么您需要匹配双引号并找到结束双引号后最左边的撇号 - 实际上,最左边的撇号不是字符串文字的一部分,是您的注释标记。
我的理解是VBA注释语法是上下文相关语法(第 1 级),因为撇号只是您的标记(如果它不是字符串文字的一部分),并且要确定撇号是否是字符串文字的一部分,最简单的方法可能是从左到右遍历字符串并切换一些IsInsideQuote
当您遇到双引号时进行标记...但前提是它们没有转义(双引号)。实际上,您甚至不检查字符串文字中是否有撇号:您只需继续行走,直到开放引号关闭,并且仅当“引号内标志”为False
如果遇到单引号,则说明您找到了注释标记。
祝你好运!
这是您缺少的测试用例:
s = "abc'def ""xyz""'nutz!" 'string with apostrophes and escaped double quotes
如果您不关心捕获字符串文字,则可以简单地忽略转义的双引号并在此处查看 3 个字符串文字:"abc'def "
, "xyz"
and "'nutz!"
.
此 C# 代码输出'string with apostrophes and escaped double quotes
(所有字符串内双引号都在代码中用反斜杠转义),并且适用于我给它的所有测试字符串:
static void Main(string[] args)
{
var instruction = "s = \"abc'def \"\"xyz\"\"'nutz!\" 'string with apostrophes and escaped double quotes";
// var instruction = "s = \"the cat's hat\" ' quote within string -- works";
// var instruction = "dim s as string ' string should be set to \"ten\"";
int? commentStart = null;
var isInsideQuotes = false;
for (var i = 0; i < instruction.Length; i++)
{
if (instruction[i] == '"')
{
isInsideQuotes = !isInsideQuotes;
}
if (!isInsideQuotes && instruction[i] == '\'')
{
commentStart = i;
break;
}
}
if (commentStart.HasValue)
{
Console.WriteLine(instruction.Substring(commentStart.Value));
}
Console.ReadLine();
}
那么如果你想捕捉所有法律意见,你需要处理遗留问题Rem
关键字,并考虑行延续:
Rem this is a legal comment
' this _
is also _
a legal comment
换句话说,\r\n
其本身不足以正确识别所有语句结束标记。
适当的词法分析器+解析器似乎是捕获所有评论的唯一方法。