用 C++ 样式注释替换 C 样式注释

Posted

技术标签:

【中文标题】用 C++ 样式注释替换 C 样式注释【英文标题】:Replace C style comments by C++ style comments 【发布时间】:2010-10-07 05:17:18 【问题描述】:

如何自动将所有 C 样式 cmets (/* comment */) 替换为 C++ 样式 cmets (// comment)?

这必须在多个文件中自动完成。任何解决方案都可以,只要可行。

【问题讨论】:

我很好奇你为什么要这样做? C++ 编译器可以很好地编译 C 风格的 cmets,那么有什么意义呢?您可能不想再添加任何 c 样式的 cmets,但不理会旧的 cmets 应该不会造成任何损失。 为什么会有人说这个问题令人反感? 这个问题是浪费时间。不是从解析的角度来看,而是它试图完成的毫无意义的任务。 -1 坦维尔。或许这是上天的旨意。如果管理层告诉你挖一个洞然后再填一遍,有时你不得不这样做,尽管毫无意义。 您需要这样做的原因可能有很多。也许你有某种预处理器或其他工具。也许您只是有一个需要遵循的编码约定。询问如何重构文本没有任何意义:我们以精心结构化的文本为生。 【参考方案1】:

这个工具可以完成这项工作: https://github.com/cenit/jburkardt/tree/master/recomment

RECOMMENT 是一个 C++ 程序 将 C 风格的 cmets 转换为 C++ 风格 厘米。

它还处理其他人提到的所有非平凡案例:

此代码包含建议和 编码于 2005 年 4 月 28 日由 JDS Uniphase 的 Steven Martin, 佛罗里达州墨尔本。这些建议 允许程序忽略 字符串的内部内容,(其中 否则似乎开始或结束 cmets), 处理代码行 带有尾随 cmets,并处理 带有尾随代码的 cmets。

【讨论】:

很遗憾,RECOMMENT 不能很好地处理缩进和格式化,而且它根本不支持 Doxygen cmets。这就是我创建c-comments-to-cpp的原因。【参考方案2】:

这不是一个小问题。

int * /* foo 
  /* this is not the beginning of a comment.

int * */ var = NULL;

你想用什么来代替它?任何真正的替换有时都需要分割线。

int * // foo
  // this is not the beginning of a comment.
// int *
var = NULL;

【讨论】:

这不是原始问题的答案。【参考方案3】:

你打算如何处理这样的情况:

void CreateExportableDataTable(/*[out, retval]*/ IDispatch **ppVal)

 //blah

注意括号内的注释...这是在生成的代码中记录事物的常用方法,或者在类的实现中提及默认参数值等。我通常不喜欢使用 cmets ,但它们很常见,需要考虑。我不认为你可以不经过深思熟虑就将它们转换为 C++ 风格的 cmets。

【讨论】:

有一个相当简单(但不受欢迎的解决方案)。如果您替换的每条评论不以 0 或空白字符和换行符结尾,则插入换行符。所以换句话说,“IDispatch **ppVal)”将在一个新行上。 别误会,我同意你的观点,转换是个坏主意 这不是答案。【参考方案4】:

我支持在您的问题中发表评论的人。为什么这样做?放手吧。

它浪费时间,向版本控制添加无用的提交,有搞砸的风险

编辑: 从 OP 的 cmets 添加详细信息

首选 C++ 风格的注释的根本原因是您可以注释掉其中可能包含 cmets 的代码块。如果该注释是 C 风格的,则代码的这种块注释不是直截了当的。 – 未知(雅虎)

这可能是一件公平/好的事情,但我有两个关于这方面的问题:

据我所知,没有人会主张更改所有现有代码 - 这是对新代码的偏好。 (海事组织) 如果您觉得需要“注释掉代码”(另一种不确定的做法),那么您可以根据需要进行 - 而不是在此之前

看来你还想用c风格的cmets来屏蔽一段代码?还是要使用 // 来屏蔽很多行?

另一种选择是针对这种情况的预处理器#ifdef。我对此感到畏缩,但这与注释掉行/块一样糟糕。两者都不应该留在生产代码中。

【讨论】:

首选 C++ 风格注释的根本原因是您可以注释掉可能包含 cmets 的代码块。如果该注释是 C 风格的,则代码的这种块注释不是直截了当的。 很公平。两点: 1. 我知道没有人会主张更改所有现有代码 - 那是对新代码的偏好。 (IMO) 2. 如果您觉得需要“注释掉代码”(另一种不确定的做法),那么您可以根据需要进行 - 而不是之前。 在我的编辑器中,注释掉可能包含 cmets 的代码块很简单,只需要两次击键。取消注释同样简单。当你可以使用一个像样的编辑器时,为什么要经历这么多麻烦? -1 因为这确实回答了操作的问题,并且主要只是说这个想法很愚蠢。这就是 cmets 的用途。【参考方案5】:

这是一个 Python 脚本,可以(大部分)完成这项工作。它处理大多数边缘情况,但它不处理字符串中的注释字符,尽管这应该很容易修复。

#!/usr/bin/python

import sys

out = ''
in_comment = False

file = open(sys.argv[1], 'r+')
for line in file:
    if in_comment:
        end = line.find('*/')
        if end != -1:
            out += '//' + line[:end] + '\n'
            out += ' ' * (end + 2) + line[end+2:]
            in_comment = False
        else:
            out += '//' + line
    else:
        start = line.find('/*')
        cpp_start = line.find('//')
        if start != -1 and (cpp_start == -1 or cpp_start > start):
            out += line[:start] + '//' + line[start+2:]
            in_comment = True
        else:
            out += line

file.seek(0)
file.write(out)

【讨论】:

【参考方案6】:

我最近将我们存储库中所有文件的所有 C 样式 cmets 转换为 C++ 样式。由于找不到可以自动执行此操作的工具,我自己编写了一个:c-comments-to-cpp

这不是万无一失的,但比我尝试过的任何其他方法(包括推荐)都要好。除此之外,它还支持转换 Doxygen 样式的 cmets,例如:

/**
* @brief My foo struct.
*/
struct foo 
  int bar;  /*!< This is a member.
                 It also has a meaning. */
;

转换为:

/// @brief My foo struct.
struct foo 
  int bar;  ///< This is a member.
            ///< It also has a meaning.
;

【讨论】:

【参考方案7】:

您为什么不编写一个 C 应用程序来解析它自己的源文件?您可以通过相对简单的 Regex 查询找到 /* cmets */ 部分。然后你可以用换行符+“//”替换换行符。

无论如何,只是一个想法。祝你好运。

【讨论】:

你到底为什么要在 C 中做这个?有很多语言比 C 更适合正则表达式搜索替换。另外,它为什么要解析“它自己的”源文件? 好吧,我可以说在 C 中做这件事只是因为大概 OP 已经知道 C。话虽如此,我想说避免在 C 中做它的相对痛苦将非常值得努力学习为这项任务提供更好的语言。我个人建议使用 Python,但有很多选择。 正则表达式是不够的,需要一个真正的解析器。 当然,如果您能够获得符合 ANSI 的 C++ 编译器的源代码,那么您就有了解析器。 :) 同意 Darron - 你不能使用正则表达式,例如 printf("////**** 这最好不要更改,它是一个字符串文字!\n");需要一个真正的 C 解析器。【参考方案8】:

如果您编写应用程序/脚本来处理 C 源文件,请注意以下几点:

字符串中的注释字符 行中间的注释字符(您可能不想拆分代码行)

您最好尝试找到一个了解如何将代码实际解析为代码的应用程序。

【讨论】:

【参考方案9】:

您可能想尝试以下一些建议:

a)编写您自己的代码(C/Python/任何您喜欢的语言)来替换 cmets。类似于正则表达式所说的内容或这种天真的解决方案 '可能' 工作: [Darron 发帖,除非像 one rmeador 这样的案例]

对于文件中的行: 如果行 [0] == "\*": buf = '//' + 行中除 '\*' 之外的所有字符 标志 = 真 如果标志 = 真: 如果行以 '*/' 结尾: 剥离 '*/' 标志 = 假 添加 '//' + 行到 buf

b) 找到一个工具来做这件事。 (我会查找一些并发布,如果我找到它们。)

c)几乎所有现代 IDE(如果您正在使用的话)或文本编辑器都具有自动注释功能。然后,您可以手动打开每个文件,选择注释行,决定如何处理这种情况并使用加速器(例如 Ctrl + M)注释 C++ 样式。然后,您可以再次使用您的判断来简单地“查找和替换”所有“/*”和“*/”。我已将 Gedit 配置为使用“代码注释”插件来执行此操作。我不记得我在 Vim 中的操作方式。我相信这个很容易找到。

【讨论】:

【参考方案10】:

如果只有“几个文件”,真的有必要编写程序吗?在文本编辑器中打开它在实践中可能会更快,除非有大量的 cmets。 emacs 有一个 comment-region 命令(不出所料)对一个区域进行 cmets,所以这只是放弃有问题的 '/*' 和 '*/' 的情况。

【讨论】:

+1。许多文本编辑器也会“在文件中查找和替换”。对于其他海报提到的所有极端情况,您无论如何都需要快速目视检查。【参考方案11】:

我知道,这是一个非常老的问题,但我只是使用“纯 emacs”实现了这一点。简而言之,解决方案如下:

运行M-x query-replace-regexp。出现提示时,输入

/\*\(\(.\|^J\)*?\)*\*/

作为要搜索的正则表达式。 ^J 是一个换行符,您可以通过按 ^Q(在大多数键盘中为 Ctrl+Q)输入,然后按 enter 键。然后输入

//\,(replace-regexp-in-string "[\n]\\([ ]*?\\)   \\([^ ]\\)" "\n\\1// \\2" \1))

作为替换表达式。

本质上,这个想法是您使用两个嵌套的正则表达式搜索。主要的只是找到 C 风格的 cmets(*? 急切的重复对此非常方便)。然后,使用 elisp 表达式执行第二次替换仅在评论文本内。在这种情况下,我正在寻找后跟空格的换行符,并将最后三个空格字符替换为 //,这对于保留注释格式非常有用(不过,只有在所有 cmets 都缩进时才有效)。

对辅助正则表达式的更改将使这种方法在其他情况下也有效,例如

//\,(replace-regexp-in-string "[\n]" " " \1))

只会将原始注释的全部内容放入单个 C++ 样式的注释中。

【讨论】:

【参考方案12】:

来自 php 团队约定...如果提出问题,则必须存在一些推理。知道就回答吧。

永远不要使用 C++ 风格的 cmets(即 // 注释)。始终使用 C 风格 cmets 代替。 PHP 是用 C 语言编写的,旨在编译 在任何符合 ANSI-C 的编译器下。尽管许多编译器 在 C 代码中接受 C++ 风格的 cmets,你必须确保你的 代码也可以与其他编译器一起编译。 此规则的唯一例外是特定于 Win32 的代码, 因为 Win32 端口是 MS-Visual C++ 特定的,而这个编译器 已知在 C 代码中接受 C++ 样式的 cmets。

【讨论】:

以上是关于用 C++ 样式注释替换 C 样式注释的主要内容,如果未能解决你的问题,请参考以下文章

使用正则表达式解析 C 样式注释,避免回溯

使用 Perl 正则表达式删除多行 C 样式 /* 注释 */

css

如何设置Eclipse/MyEclipse代码注释样式

css层叠样式表

Doxygen C预处理器宏文档样式