有没有一种方法可以区分注释性代码和注释性代码?


36

在整个编程过程中,您将最终得到一些解释代码的注释和一些除去代码的注释:

// A concise description 
const a = Boolean(obj);
//b = false;

有什么好的方法可以快速解析哪个?

我一直在使用3 //** */描述性注释。

我还使用了VSCode插件来突出显示//TODO://FIXME:


2
作为一个说明,////** ... */评论也被一些文档生成,如使用Doxygen或JSDoc。如果您使用它们或类似的工具,则可能无法将此类注释用于不属于本文档一部分的描述性注释。
贾斯汀时间2恢复莫妮卡

1
在javascript中,大多数代码行都可能以分号结尾。除非您的评论这样做,否则这似乎很简单,并且您也可以编写脚本来轻松地进行检查。
Artemis Fowl

Answers:


187

有一个非常简单的解决方案:删除注释掉的代码。

确实,注释掉代码只有两个很好的理由:测试某些东西/进行修复,或者保存以后可能使用的代码。如果要测试或修复某些问题,请在完成测试或修复后立即删除注释掉的代码。如果您要保存代码,则可以在以后使用,请将其设置为一流的代码,然后将其放置在诸如库之类的可以充分利用的位置。


108
另外,如果代码已签入:只需将其删除。如果您需要它,可以使用源代码管理
marstato

38
删除代码后,没人会注意到它曾经存在。这使得恢复变得更加困难。留下注释的代码很有用,特别是如果将来有可能使用它。
usr

76
@usr:删除代码后,没人会注意到它曾经存在过 -以我的经验,在所有现实世界中有99%的情况是正确的。在1%的值中,注释过的行可能会有一些价值,但是,如果注释掉的代码停留了几周或几个月(或更长时间),则由于活动代码的重构,机会很大,甚至无法再编译代码行。对于那些在情感上将事物从代码库中剥离出来的人来说,“为将来使用的潜在价值”这一论点经常被用作错误的借口,因为他们花了一些时间进行脑力劳动。
布朗

21
没有附加的解释性注释,我永远不会提交注释的代码。在极少数情况下,您可能需要在短期内恢复代码,但是其中的每一个都是例外,需要为将来的开发人员(或将来的您)提供解释。我90%的评论是“已删除,因为它似乎未被使用。如果没有问题,请在2021年11月之后删除”
James Beninger

30
当我们暂时删除某些功能时,我的同事曾经说过“这里有执行X的代码,但我删除了”。那真的很好。您知道它在该文件的源历史记录中,但它并没有打扰您。
Erik

45

添加到@RobertHarvey的出色答案中,我相信将注释的代码保存到源代码管理中,即使是暂时的,也只有一个合理的理由:在非显而易见的替换代码的情况下,出于某些原因现在不应该或不能使用。即使这样,大多数注释也应该是解释,而不是替换代码。这可能是语言的错误或功能,目前尚未被认为是稳定的。它可能看起来像这样:

# TODO: Replace with `foo = frobnicate(bar)` once <link.to/bug> is fixed
foo = [some complex workaround]

在这种情况下,工作已经完成,但是您还不能利用它,因此删除它意味着以后必须重新发现它。这同样适用于次优的解决方案,似乎在它的面前上级反对类似的解决方案有意识的权衡

警告:不要用其他解决方案乱扔代码。每个任务都可以通过许多不同的方式来完成,并且长时间进行每次更改都无法节省成本。当您的同事建议您发现改进不够理想时,代码审查可能是发现此类缺失注释的好地方。


2
另一方面,有时您需要解释为什么不使用frobnicate(bar),所以没有人会尝试“修复”您的“模糊”代码。因此,您向他们表明,您知道在一个完美的世界中,frobnicate功能是必经之路,但是从痛苦的经历中您知道,它无法正常工作。也许没有人希望第三方甚至认为它是错误,更不值得修复。您仍然需要向以后的程序员(包括您自己)发表评论,说明为什么您没有采用明显的方法。
蒙迪·哈德

3
与此相关的情况是,可能有两种方式执行某项操作,一种方式将比另一种方式更快地处理有效数据,而另一种方式则可以(无论出于何种原因)接收到无效数据,从而提供更有用的诊断。如果程序是进程的一部分,而该进程仅应向其提供“保证”有效的数据,但进程中的某些功能无法正常工作,则可以使用较慢的版本,但提供更好的诊断功能,从而可以使其更容易确定出了什么问题。
超级猫

20

嗯,我读到的这个问题与罗伯特(Robert)略有不同,罗伯特(Robert)正确断言应删除注释掉的代码。

但是,如果您正在寻找标记代码以便以后删除的约定,则我的最喜欢的是:

//b = false; //TODO: remove

//TODO:或可以教一些IDE的标志注释。如果不是,则通常是可搜索的字符串。最好遵循您的商店建立的任何约定,因为这可以通过几种方法完成。每个代码库都应以一种方式执行此操作。使其可搜索。

快速解析哪个是哪个?

没有该标记的自动方法就是使用编译器。如果剥离注释产生了可编译的代码,则该注释必须是注释代码。编写一个IDE插件进行检查,这并不难。但这会留下越野车注释的代码。

这就是为什么最好在注释掉后立即将注释掉的代码标记为代码。这样一来,您就可以决定是否确实要删除它,而进行无损工作。由于我们都被打断了,并且有些健忘,所以如果在该状态下检查某些行,不要感到惊讶。如果他们这样做了,那么至少可以清楚地标记和搜索它们就很好了。过去,键盘宏已经帮助了我。如果您可以通过一次按键操作就很难被打断。

您可以在连续集成测试中尽可能多地标记。糟糕,我正尝试再次与出色的TODO签到。


您无需查看注释是否可以编译为将其标记为代码,而是可以通过自然语言处理器运行注释,并将注释解析为使用您团队所用语言的句子或名词短语。
TheHansinator

3
@TheHansinator听起来不错,但我的手机使用经验与编码器术语会自动正确建立关系,这使我变得谨慎。
candied_orange

我想,用于解析代码注释的NLP会比支持自动更正的NLP好得多,这仅仅是因为计算机具有整个句子都可以使用并且不试图纠正拼写错误。更不用说假阴性在这里也更好-只要人们能够在删除之前查看评论,他们就可以重写评论,而不是不被警告无用的傻瓜。
TheHansinator

3
wrt解析:double buffer (flip on)-> C原型还是超简洁英语?没有上下文就无法分辨,这两种语言都不能构成正确的整体结构。当评论的性质不会在任何方向上限制其内容的形式时,不可避免地会出现一些误报。
Leushenko

8

我使用预处理器指令删除代码,而不是注释:

//comment
active_code();
#if FALSE
inactive_code();
#endif

这使搜索变得非常容易,并且我的语法荧光笔将其视为注释。我什至可以将其折叠成一行:#if FALSE(...)

您可以扩展该想法以提供多种选择:

#if OPTION == 0
code_for_option_0();
#elif OPTION == 1
code_for_option_1();
#else
code_for_all_other_options();
#endif

并进行编译时错误检查:

#if FOO >= 5
#error FOO should be less than 5!
#endif

当然,您不想对此太过费力,否则很难告诉您实际正在编译的内容和未编译的内容。但是,您了解了这个主意,无论如何,只要您仅静态使用它,它就和注释代码一样是一个问题。如果您的条件是动态的,那就更糟了。


要确定在现有代码库中哪个根本没有考虑此问题,我认为没有通用的解决方案。您必须自己找到模式,并可能编写一个正则表达式来查找它们。


这对世界有什么好处?您需要编译多个版本吗?
Tvde1

@ Tvde1这是一个可能性,以及潜在的噩梦,如果你不管理它真的很好。但是替代方案可能更糟。如果您有几乎相同代码的多个副本,一个通用主题的每个变体一个,则必须分别维护它们并保持同步。
亚伦

有几种方法可以执行此操作,但是它们都对复杂的配置问题或独立副本问题有所不同:您确定所有独立副本都存在错误修正吗?如果没有,又添加了另一个功能,然后又被该功能之前已知但尚未移植的错误修复所破坏,该怎么办?
亚伦

3
仅当您具有类似C的预处理步骤时,此方法才有效。问题是关于javascript。您可以进行一些预处理,但这将扩展构建系统的功能,而且它也是非标准的。如果您没有构建系统,或者构建系统完全不支持解析和执行代码,则将无法实现此解决方案。最后,它甚至没有解决问题-注释掉的代码并不严格等同于有条件激活的代码。这可能是一个剩余的,本来就不应该启用。
VLAZ

条件激活只是答案的扩展,而不是答案本身。否则,我将对其进行编辑以包含进一步扩展它的注释。
亚伦

4

我同意答案,指出应该删除旧代码而不是在可能的情况下将其注释掉,但是我观察到在少数情况下需要注释掉代码的约定。

(我的基础是C#,但是它可以应用于任何C语法语言,例如java)

// An explanatory comment has a space between the comment marker and the content.

// The following lines are commented out code so do not have the space (except where indented).
//var a = something();
//if(a==2) {
//   doSomethingElse();
//}

2
这完全取决于样式:在注释掉代码时,通常将添加//到第一列,并且由于实际上所有代码都是缩进的,因此结果实际上总是注释以某些选项卡开头。普通评论不会在我面前占主导地位,除非附近已经有其他带有领导空格的评论。因此,您的方法将对我产生的注释失败,而任何旨在识别我的注释模式的方法将对您的失败。
cmaster

@cmaster啊,我明白了,我想我误解了这个问题。我提供了一种格式化注释的简单方法,以便可以轻松地分析注释的类型,而这并不是要求的。
IanF1

2

我仍在解释问题,认为您想找到注释掉的代码。

C风格的代码注定要包含分号,而注释不太可能包含分号。因此,对于单行注释掉的代码,您可以使用以下正则表达式:

\s*\/\/[\s\S]*;

对于多行注释掉的代码,可能是

\/\*[^\;]*;[^\;]*\*\/

注意Visual Studio对于正则表达式中的换行符有点特殊,它们不算作空格,您需要指定一个显式\ n。


2

如果使用在后台运行编译器的编辑器(例如Xcode和Clang),则可以尝试编译注释文本。例如,“简洁的描述”会给出错误,而“ b =假;”则不会。然后,您可以使用其他语法突出显示。

一个更简单的方法是使用一些启发式的IDE插件,例如连续多个单词(关键字以外的单词指向注释),匹配的花括号指向代码等。


1

其他答案涵盖了“不注释代码”主题的变体。但是有时您仍然希望它能为您提供参考。

如果您确实需要保留代码,那么更好的解决方案是用“ #if 0 ... #endif”将代码括起来,最好用注释说明原因。这是各种编码标准(包括MISRA)推荐的策略。


-3

简单,至少对我来说-和C / C ++。/ * * /中包含的注释是提供信息的。暂时删除的测试代码以//开头注释。

并且有充分的理由将测试代码保留在文件中,但至少在我所做的工作中被注释掉了。迟早有人会想要进行更改,这需要该代码。取消注释一个块需要一个编辑器命令,就像在完成后重新注释一样。


还有#ifdef __DEBUG ... #endif,或您要使用的任何自定义定义。 __DEBUG很好,因为您通常只需要更改项目配置即可。但是大多数IDE都可以让您定义自己的配置,这可以为您提供任何便利。
亚伦

“测试代码”是什么意思?单元测试?这些内容根本不应该被注释掉,而应保留在测试套件中并尽可能频繁地运行,而不管是否有人认为有必要。当然,重新注释一段代码很容易,但是完全不做任何事情并且已经准备好测试套件就更容易了……
大约在

1
啊,不要那样做。注释掉代码“测试某件事”将可以很好地完成100次中的99次...并且在单个情况下,您会忘记删除它(如果不再需要它),或者甚至更糟的是,忘记对其取消注释(如果需要),事情可能会变得难看。
CharonX

@leftaroundabout:不,我的意思是将诸如printf语句之类的内容用于检查值。
jamesqf

@jamesqf,您永远都不需要那种东西,这就是调试器的用途。但是,即使您使用printf/ cout或类似方法正确地编写了新代码(我也承认我以前做过这些事情),将它们留在那儿并不是很有效。如果有人要进行更改并知道他们需要有关哪些变量的信息,则printf重新编写s 很快又容易,而如果该开发人员知道需要什么并且只取消注释了所有这些printf语句,则大量文本终端可能也不会帮助他们。
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.