我正在尝试捕获VBA评论。到目前为止,我有以下内容
'[^";]+\Z
它捕获以单引号开头但在字符串结尾之前不包含任何双引号的任何内容。即它不会匹配双引号字符串中的单引号。
dim s as string ' a string variable -- works
s = "the cat's hat" ' quote within string -- works
但如果评论包含双引号字符串
,则会失败即
dim s as string ' string should be set to "ten"
我如何修复我的正则表达式呢?
答案 0 :(得分:5)
@Jeff Wurz's comment(^\'[^\r\n]+$|''[^\r\n]+$
)中的模式甚至不匹配任何您的测试样本,并且链接的问题无用,那里的正则表达式将是只匹配OP的问题中的特定评论,而不是" VBA评论语法"。
你提出的正则表达式比我放弃正则表达式时所做的更好。
干得好!
问题在于您无法使用正则表达式解析VBA注释。
在Lexers vs Parsers中,@SasQ's answer在解释乔姆斯基的语法水平方面做得很好:
第3级:常规语法
他们使用正则表达式,也就是说,它们只能包含 字母符号(a,b),它们的连接(ab,aba,bbb etd。),或 替代方案(例如a | b)。它们可以实现为有限状态 自动机(FSA),如NFA(非确定性有限自动机)或更好 DFA(确定性有限自动机)。 常规语法无法处理 使用嵌套语法,例如正确嵌套/匹配的括号 (()()(()())),嵌套的HTML / BBcode标签,嵌套块等。它是因为 国家自动机处理它应该有无限多 处理无限多的嵌套级别。
第2级:无上下文语法
他们的语法中可以有嵌套,递归,自相似的分支 树,所以他们可以很好地处理嵌套结构。他们可以 实现为具有堆栈的状态自动机。这个堆栈用于 表示语法的嵌套级别。在实践中,他们是 通常实现为自上而下,递归下降的解析器使用 机器的过程调用堆栈来跟踪嵌套级别,并使用 递归地称为每个非终端符号的过程/函数 在他们的语法中。但他们无法处理上下文相关的问题 句法。例如。当你有一个表达式x + 3并且在一个上下文中这个x 可以是变量的名称,在其他上下文中它可以是名称 功能等。
第1级:上下文相关语法
正则表达式根本不是解决此问题的合适工具,因为只要有多个引号(/撇号),或者涉及双引号时,您需要弄清楚是否代码行中最左边的撇号是双引号,如果是,那么你需要匹配双引号并在结束双引号后找到最左边的撇号 - 实际上,最左边的撇号是&#39 ; t字符串文字的一部分,是你的评论标记。
我的理解是VBA注释语法是上下文敏感语法(级别1),因为如果撇号不是字符串文字的一部分,那么撇号只是你的标记,并且弄清楚撇号是否是字符串文字的一部分,最简单的可能是从左到右走你的字符串,并在你遇到双引号时切换一些IsInsideQuote
标志...但只有当它们是“重复”时没有逃脱(加倍)。实际上你甚至不检查字符串文字中是否有撇号:你只是一直走,直到打开的引号被关闭,并且只有当引用标记为"" in-quotes flag"如果您遇到单引号,则False
您找到了评论标记。
这是您缺少的测试用例:
s = "abc'def ""xyz""'nutz!" 'string with apostrophes and escaped double quotes
如果您不关心捕获字符串文字,则可以忽略转义的双引号,并在此处查看3个字符串文字:"abc'def "
,"xyz"
和"'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
本身并不足以正确识别所有语句结束标记。
正确的词法分析器+解析器似乎是捕获所有注释的唯一方法。