当//注释出现在/ * * /中时,sed用/ * * / comments替换//除外

我面临的问题是ANSI编译器需要C样式注释。

所以我试图将我现有的注释转换为符合C标准ISO C89。

我正在寻找一个SED表达式来替换//注释/ *注释除了//注释出现在/ * * / comments中(这会破坏注释)。

我试过这个(范围表达式)无济于事:

sed -e '/\/*/,/*\//! s_//\(.*\)_/*\1 */_' > filename 

有些东西可以忽略这样的评论中的1行注释,但改变其他一切吗?

 /********************************** * Some comment * an example bit of code within the comment followed by a //comment * some more comment ***********************************/ y = x+7; //this comment must be changed 

谢谢!

这是一个用C语言编写的经过轻度测试的filter,可以执行您想要的转换。 关于这个filter做什么的一些评论即使不是不可能用正则表达式处理也很困难:

  • 它忽略了用引号括起来的类似注释的序列(因为它们不是注释)
  • 如果正在转换的C99注释包含可以开始或结束C89注释的内容,则它会弹出该序列,因此注释中不会有嵌套注释或过早结束(嵌套/**/更改为/+/| )。 我不确定你是否需要这个(如果你不需要,它应该很容易删除)
  • 上面嵌套注释的修改只发生在正在转换的C99注释中 – 已经C89样式的注释内容不会更改。
  • 它不处理三字符或有向图(我认为这只允许错过一个转义序列或以三字符??/启动的行结束延续的可能性)。

当然,您需要执行自己的测试以确定它是否适合您的目的。

 #include  char* a = " this is /* a test of \" junk // embedded in a '\' string"; char* b = "it should be left alone//"; // comment /* that should ***//// be converted. /* leave this alone*/// but fix this one // and "leave these \' \" quotes in a comment alone* /**** and these '\' too // */ enum states { state_normal, state_double_quote, state_single_quote, state_c89_comment, state_c99_comment }; enum states current_state = state_normal; void handle_char( char ch) { static char last_ch = 0; switch (current_state) { case state_normal: if ((last_ch == '/') && (ch == '/')) { putchar( '*'); /* NOTE: changing to C89 style comment */ current_state = state_c99_comment; } else if ((last_ch == '/') && (ch == '*')) { putchar( ch); current_state = state_c89_comment; } else if (ch == '\"') { putchar( ch); current_state = state_double_quote; } else if (ch == '\'') { putchar( ch); current_state = state_single_quote; } else { putchar( ch); } break; case state_double_quote: if ((last_ch == '\\') && (ch == '\\')) { /* we want to output this \\ escaped sequence, but we */ /* don't want to 'remember' the current backslash - */ /* otherwise we'll mistakenly treat the next character*/ /* as being escaped */ putchar( ch); ch = 0; } else if ((ch == '\"') && (last_ch != '\\')) { putchar( ch); current_state = state_normal; } else { putchar( ch); } break; case state_single_quote: if ((last_ch == '\\') && (ch == '\\')) { /* we want to output this \\ escaped sequence, but we */ /* don't want to 'remember' the current backslash - */ /* otherwise we'll mistakenly treat the next character*/ /* as being escaped */ putchar( ch); ch = 0; } else if ((ch == '\'') && (last_ch != '\\')) { putchar( ch); current_state = state_normal; } else { putchar( ch); } break; case state_c89_comment: if ((last_ch == '*') && (ch == '/')) { putchar( ch); ch = 0; /* 'forget' the slash so it doesn't affect a possible slash that immediately follows */ current_state = state_normal; } else { putchar( ch); } break; case state_c99_comment: if ((last_ch == '/') && (ch == '*')) { /* we want to change any slash-star sequences inside */ /* what was a C99 comment to something else to avoid */ /* nested comments */ putchar( '+'); } else if ((last_ch == '*') && (ch == '/')) { /* similarly for star-slash sequences inside */ /* what was a C99 comment */ putchar( '|'); } else if (ch == '\n') { puts( "*/"); current_state = state_normal; } else { putchar( ch); } break; } last_ch = ch; } int main(void) { int c; while ((c = getchar()) != EOF) { handle_char( c); } return 0; } 

一些放纵的评论:很多年前,我工作过的一家商店想强加一个禁止C99风格评论的编码标准,理由是即使我们当时使用的编译器没有问题,代码可能必须是移植到不支持它们的编译器。 我(和其他人)成功地认为这种可能性是如此遥远,以至于基本上不存在,并且即使它确实发生了,也可以很容易地编写使评论兼容的转换例程。 我们被允许使用C99 / C ++风格的评论。

我现在认为我的誓言已经实现了,而且可能已经解除了我的任何诅咒。

如果你不能使用@ephemient的建议,那么你需要跨多行应用你的正则表达式,这不是sed的默认行为。 sed有一个保持缓冲区,它允许你将多个字符串附加在一起并将正则表达式应用于连接字符串。

sed表达式如下所示:

 sed '1h;1!H;${;g;s/your-matcher-regex/replacement-regex/g;}' 

1h – 如果是第一行,将该行放入保持缓冲区(首先将其清空)

1!H – 如果不是第一行,则附加到保持缓冲区

$ {...} – 如果是最后一行,执行此sed命令

现在,即使/ *和* /在不同的行上,您的matcher表达式也会起作用。

 awk '{if($0~/\/\//){sub(/\/\//,"\/\*");$0=$0"*/"};print}' temp 

使用任何可以为/*//注释输出不同标记的转换器将代码转换为彩色HTML,使用perl / awk / sed / whatever处理输出,然后剥离标记。

您可以(几乎)完全在sed中执行此操作,您只需要调用tr

translate_comments_prepare.sed

 s/\\/\\\\/g # escape current escape characters s/\$/\\S/g # write all occurrences of $ as \S s/(/\\o/g # replace open braces with \o s/)/\\c/g # replace closing braces with \c s/$/$/ # add a $ sign to the end of each line s_/\*_(_g # replace the start of comments with ( s_\*/_)_g # replace the end of comments with ) 

然后我们通过tr -d '\n'管道“预处理”步骤的结果来连接所有行(我还没有找到一个从sed执行此操作的好方法)。

然后我们做真正的工作:

translate_comments.sed

 s_//\([^$]*\)\$_(\1)$_g # replace all C++ style comments (even nested ones) :b # while loop # remove nested comment blocks: # (foo(bar)baz) --> (foobarbaz) s/(\([^()]*\)(\([^()]*\))\([^()]*\))/(\1\2\3)/ tb # EOF loop s_(_/*_g # reverse the steps done by the preparation phase s_)_*/_g # ... s/\$/\n/g # split lines that were previously joined s/\\S/$/g # replace escaped special characters s/\\o/(/g # ... s/\\c/)/g # ... s/\\\(.\)/\1/g # ... 

那我们基本上把所有东西放在一

 sed -f translate_comments_prepare.sed | tr -d '\n' | sed translate_comments.sed 

这可能适合你(GNU sed):

 sed ':a;$!{N;ba};s/^/\x00/;tb;:b;s/\x00$//;t;s/\x00\(\/\*[^*]*\*\+\([^/*][^*]*\*\+\)*\/\)/\1\x00/;tb;s/\x00\/\/\([^\n]*\)/\/*\1\*\/\x00/;tb;s/\x00\(.\)/\1\x00/;tb' file 

说明:

  • :a;$!{N;ba}将文件放入模式空间
  • s/^/\x00/设置标记NB这可以是文件中找不到的任何字符
  • tb;:b通过跳转到占位符b来重置替换开关
  • s/\x00$//;t标记已到达文件末尾。 全部完成。
  • s/\x00\(\/\*[^*]*\*\+\([^/*][^*]*\*\+\)*\/\)/\1\x00/;tb这个正则表达式匹配c样式注释并且如果为真则标记传递它们。
  • s/\x00\/\/\([^\n]*\)/\/*\1\*\/\x00/;tb这个正则表达式匹配单行注释,替换为c样式注释并碰撞标记如果是真的,就通过了
  • s/\x00\(.\)/\1\x00/;tb这个正则表达式匹配任何单个字符,如果为真,则碰撞传递它的标记。