C#方法内容验证

4

我需要验证一个C#方法的内容。

我不关心不影响方法范围的语法错误。

但我会关注那些会使其余代码无法解析的字符。例如:

method()
{
  /* valid comment */
  /*           <-- bad
  for (i..) {
  } 
  for (i..) {  <-- bad
}

我需要验证/修复任何没有成对出现的字符。

这包括 /* */, { },可能还有其他字符。

我该怎么做呢?

我的第一个想法是使用正则表达式,但显然这并不能完成工作。

5个回答

3

为了获得合理的答案,您需要更仔细地限定问题范围。

例如,您打算如何处理包含预处理器指令的方法?

void M()
{

#if FOO
    for(foo;bar;blah) {
#else
    while(abc) {
#endif
        Blah();
    }
}

这很荒谬但是合法,所以你必须处理它。你会将其视为不匹配的大括号还是不会?

你能否提供一个详细的规范来确定你想要的内容?正如我们在本网站上多次看到的那样,人们无法成功构建除两个数字之外的例程而没有规范。你所说的分析比除两个数字更复杂;实际编译器中执行你所描述的功能的代码有数万行之多。


我不需要绝对的解决方案。我试图提供的是一个简单的指示,表明代码中可能存在错误。
  1. 如果代码包含预处理器语句,则不执行任何操作。这是我的用户的边角情况,并且更难以解决一个数量级。
  2. 如果代码包含未匹配的 { 或 /*,则将其突出显示。
这并不是很详细,但它确切地说明了我所需要的。
- jaws
@user258651:好的,那字符串呢?假设你的代码有不匹配的大括号,但包含 Console.WriteLine("}}}}}"); —— 这些算作括号结束吗? - Eric Lippert
@user258651: 如果一个注释中包含大括号,您是否将其视为结束的大括号? - Eric Lippert
@user258651: 另外,我注意到,“如果代码包含预处理指令,则不执行任何操作”的逻辑上要求您必须编写预处理指令探测器,否则您就不知道是否要执行任何操作。 - Eric Lippert
你说得对,在所有方面都是这样。这是我必须投入大量研究时间的事情。我寻找的简单解决方案根本不存在。 - jaws

1

正则表达式绝对不是解决这个问题的答案。正则表达式是某些类型数据验证的有用工具。但一旦你涉及到更复杂的数据,比如匹配括号或注释块,正则表达式就不能胜任了。

这里有一篇关于使用正则表达式验证输入时遇到的限制的博客文章。

为了实现这一点,您需要编写一种解析器来进行验证。

1

一个正则表达式对于这样的任务并不是很方便。通常使用以下算法和堆栈来实现:

  1. 创建一个空栈S。
  2. 当还有剩余字符时,执行以下操作:
  3. 读取一个字符ch。
  4. 如果ch是任何一种开放括号,则将其推送到S中。
  5. 否则,如果ch是任何一种闭合括号,则查看S的顶部。
  6. 如果此时S为空,则报告失败。
  7. 如果S的顶部是与c相对应的开放括号, 然后弹出S并继续执行1,这个括号匹配成功。
  8. 否则报告失败。
  9. 如果在输入结束时堆栈S不为空,则返回失败。 否则返回成功。

欲了解更多信息,请查看http://www.ccs.neu.edu/home/sbratus/com1101/lab4.htmlhttp://codeidol.com/csharp/csharpckbk2/Data-Structures-and-Algorithms/Determining-Where-Characters-or-Strings-Do-Not-Balance/


第四步是不正确的,因为您必须考虑注释。以下代码将被注册为有效,但实际上是无效的:foo(//) - JaredPar
正则表达式可以帮助忽略注释或字符串中的内容,而且你可以一次性匹配整个内容,无需解析器状态。 - Simon Buchan
@JaredPar:一行注释只是一个以“//”开头,以“\n”结尾的匹配。它与块注释或字符串没有任何区别。 - Simon Buchan
@Simon,所提到的算法没有忽略注释,因此它们的实现是不正确的。 - JaredPar
@jaredpar 你说得完全正确。我认为它包含了我留下的一般想法,将边缘情况添加到读者的练习中... ;) - olle

0
你在“会使得代码解析无效的字符”和“语法错误”之间建立了一个虚假的二分法。缺少闭合花括号(你提到的问题之一)是一种语法错误。看起来你的意思是要寻找可能破坏作用域边界的语法错误?不幸的是,除非使用完整的解析器,否则没有稳健的方法来实现这一点。
举个例子:
method()
{ <-- is missing closing brace
  /* valid comment */
  /*           <-- bad
  for (i..) {
  } 
  for (i..) {  
} <-- will be interpreted as the closing brace for the for loop

没有一种通用的、实用的方法可以推断缺少闭合大括号的是 for 循环,而不是方法。

如果你真的对这些事情感兴趣,你应该考虑以编程方式运行编译器并解析结果——这是最低门槛的最佳方法。


该方法的大括号不是我要验证的部分,只有字符串中的内容需要进行验证。 - jaws
我之前考虑过这个问题,认为使用缩进来确定最后一个大括号是对应该方法的是完全没有问题的。 - Simon Buchan
@user258651 抱歉 - 我可能误解了你的代码示例。那么你在第二个for循环中的"<-- bad"是什么意思? - Dathan
@Simon 你可能是对的,因为目标似乎是一个信息工具而不是需要严格正确性的工具,而且大多数代码现在都有很好的缩进。 - Dathan
"for (i..) { <-- bad" 是错误的,因为没有 } 匹配。我只对验证方法的内容感兴趣,即括号内的所有内容(但不包括括号本身)。 - jaws

0

如果你想要“验证”一个定义方法的字符串的内容,那么最好尝试使用CodeDom类,在内存中动态编译该方法为一个程序集。

编写一个完全功能的解析器来进行验证将会非常困难,特别是如果你想要支持C# 3或更高版本。Lambda表达式和其他类似的结构将会非常难以“干净地”进行验证。


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接