65.9K
CodeProject 正在变化。 阅读更多。
Home

C# 中的源代码取消注释器

starIconstarIcon
emptyStarIcon
starIcon
emptyStarIconemptyStarIcon

2.09/5 (6投票s)

2009年9月8日

CPOL

4分钟阅读

viewsIcon

28887

downloadIcon

1041

首批删除多种 C 风格语言(C、C++、Java 和 C#)中注释的 C# 应用程序之一

引言

您是否是一名开发人员,觉得阅读代码比阅读注释更容易,但发现分析代码有多困难,以及一个函数/过程有多简单?您是否曾经想过重新编写包含 20 多页(或更多)代码的文档,并且知道逐行删除注释有多么繁琐?或者您是否正在考虑在传输代码之前如何“稀释”您的代码,以减少网络传输时间。

编译程序时,代码中的注释会发生什么情况?本文深入介绍了这些内容,并提供了一个工具,用于删除 ASCII 源代码文件中的现有注释。

工作原理

普通的编译器不理解注释。它只是简单地跳过它们。但是,在纯文本源代码中保留它们很可能会在编译过程中引起问题。因此,为了克服这种情况,大多数 C 风格的语言使用 /* */ 或 // 来表示注释。这将标记编译器/解释器不要“读取”后面的内容

int x;    //commentary about an unknown alien x, in one line

或者

int x;    /* Tell me more about the 
    stars and the moon, in an essay */

那么,您是否想知道在您按下编译按钮的那一刻,那些讨厌的注释会发生什么?它们被丢弃了!好吧,我的意思是它们保留在源文件中。惊讶吗?如前所述,注释不是为编译器准备的!话虽如此,可以将注释存储在二进制文件的元数据部分。(尽管我不知道有哪个编译器实现了这个功能,即使有,也会牺牲很多性能)

以 Java 中的这段代码为例

            
/**

* {@link Class#getSimpleName()} is not GWT compatible yet, so we

* provide our own implementation.

*/

@VisibleForTesting

static String simpleName(Class<?> clazz) {

    String name = clazz.getName();

    // we want the name of the inner class all by its lonesome

    int start = name.lastIndexOf('$');

    //if this isn't an inner class, just find the start of the

    // top level class name.

    if (start == -1) {

    start = name.lastIndexOf('.');

    }

    return name.substring(start + 1);

}
        

当您编译代码时,编译器会看到它像这样

 

@VisibleForTesting

static String simpleName(Class<?> clazz) {

    String name = clazz.getName();

 

    int start = name.lastIndexOf('$');

 

    if (start == -1) {

        start = name.lastIndexOf('.');

    }

 

    return name.substring(start + 1);

}

因为注释是在运行时被删除的。这就是编译器生成对象和/或机器代码所需要的一切!删除注释总是在编译之前完成的,而且通常对开发人员来说是透明的。

我今天在这里介绍的应用程序实现了这个功能。给定一个文本源文件,它可以删除注释,留下可以编译的代码。当您希望重新编写别人的或您自己的代码,而无需手动逐行删除代码时,这会很方便。在示例屏幕截图中,所有单行、多行甚至 Javadoc 注释都被删除。同样,在 C# 中,XML 注释也被删除。

算法概述

基本规则是,当在代码行中找到单行 (//) 注释时,程序应停止读取,直到遇到新行 ('\n'),然后读取下一行。

当找到多行 (/*) 标记时,程序应停止处理,直到找到 */ 为止。"\n" 或 "*/" 将状态恢复正常。

在此实现中,使用 StreamReader 读取我们的 ASCII 源代码。由于代码是使用 readLine() 方法逐行处理的,因此检测和处理注释分隔符变得稍微困难一些。许多用 C 编写的编译器实现(例如 gcc)都在逐字符地解析代码,以提高性能和优化。但是,我们正在开发的远不是一个成熟的编译器,因此逐行处理应该足够了。

我设法将其保持在最少的 2 个方法,即主方法 doUncomment() 和一个用于处理字符串文字的内部方法。所有方法都实现为 static,因此无需创建实例。有关更多信息,请参阅 Uncommenter 类。

使用代码

要使用该代码,请插入指令

 using UcommenterCS;

然后简单地调用 static 函数来完成工作。例如

Uncommenter.doUncomment("src.cpp");	//specify full path

就是这样。

但是,如果您希望“开箱即用”地单独运行它,或者只是想尝试一下,我包含了一个编译后的二进制文件,它同样好。它位于 /bin 文件夹中。要使用它,请发出以下命令

 UcommenterCS <source.cpp/c/cs/java/h/js>

解析能力

应避免在字符串分隔符中使用注释。此应用程序能够正确地确保注释不是字符串的一部分!它忽略 "" 块之间的注释分隔符。

未来的功能包括检测和警告未终止的块注释和字符串文字,并可以选择在发现它们时中断执行。

因为我不是编译器语言学家,所以我无法想到代码可能失败的所有可能情况。但是,如果您愿意接受挑战,欢迎您尝试破解我的代码。如果发生这种情况,请务必告诉我。

历史

  • 第一个版本 - 7 月 9 日
  • 第二次更新(在不同的类名和命名空间下重新打包并更改为静态方法)   - 9 月 14 日

我计划在不久的将来编写一个 Window Forms 版本。还在开发中的是 Java 版本。

© . All rights reserved.