【问题标题】:Adapt perlfaq script to remove C and C++ comments to instead perform search and replace within C and C++ comments调整 perlfaq 脚本以删除 C 和 C++ 注释,改为在 C 和 C++ 注释中执行搜索和替换
【发布时间】:2012-06-18 12:56:47
【问题描述】:

我的任务是(尝试)在大型代码库中搜索和替换单词后缀,仅当它出现在 cmets 中时。所有的 cmets 都是 /* 或 // 类型,但它们保证包括大多数可以想象的边缘情况。

所以我想改变这个:

/* blah blah something__suffix blah */

到这里:

/* blah blah something blah */

但我也想改变这个:

// blah blah something__suffix blah 

到这里:

// blah blah something blah 

还有这个:

/*
 * blah blah something__suffix blah 
 */

到这里:

/*
 * blah blah something blah 
 */

还有这个:

/** 

// blah blah something__suffix blah 

*/

到这里:

/** 

// blah blah something blah 

*/

令人作呕(字面意思)。

最初我觉得这是一个解析器任务,我安装了 cochinelle,它确实可以解析我的 cmets,但它被我的预处理器宏卡住了,对于那些只将其作为一次性任务的人来说,解决方法似乎很复杂。所以现在我正在考虑正则表达式。

我没有找到很多关于在 C 和 C++ cmets 中使用正则表达式进行真正强大的搜索和替换的建议(除了“你需要一个解析器”),但我确实注意到似乎有一条很好的道路- 在 perl FAQ 上测试了 perl 脚本,用于删除这两种样式的 cmets here

如下:

$/ = undef;
$_ = <>;

s#/\*[^*]*\*+([^/*][^*]*\*+)*/|//([^\\]|[^\n][\n]?)*?\n|("(\\.|[^"\\])*"|'(\\.|[^'\\])*'|.[^/"'\\]*)#defined $3 ? $3 : ""#gse;

print;

我的问题:如何修改此脚本,以便可以搜索已识别为评论的文本以查找后缀并删除后缀,而不是剥离评论,从而使评论的其余部分保持不变?

【问题讨论】:

  • 注意@daxim 的链接,那里接受的答案似乎不能处理字符串。所以这个表达式可能更健壮。
  • 那个Regexp::Common 真的很棒,不知道。谢谢达西姆。
  • @Qtax 你能举一个它不处理的字符串的例子吗?
  • @Halle,x = "hello there /* oops this is not a comment */";。字符串中的“comment”将被匹配。虽然这个表达式能正确处理字符串。

标签: c++ c regex perl comments


【解决方案1】:

我不确定这是否是一个好的解决方案,但它确实有效。

use strict; use warnings; use feature qw(say);
my @lines = (
qq~Example 1:
/* blah blah something__suffix blah */~,
qq~Example 2:
// blah blah something__suffix blah needs a newline at the end
~,
qq~Example 3:
/*
 * blah blah something__suffix blah 
 */~,
qq~Example 4:
/** 

// blah blah something__suffix blah 

*/~,
qq~Example 5 (string):
foobar '// blah blah something__suffix blah '~,
qq~Example 6:
public void main { return; } // this does__suffix nothing but needs newline
~,
);

foreach (@lines) {
  print "Before:\n$_\n";
  s!/\*[^*]*\*+([^/*][^*]*\*+)*/|//([^\\]|[^\n][\n]?)*?\n|("(\\.|[^"\\])*"|'(\\.|[^'\\])*'|.[^/"'\\]*)!
  { if (defined $3) { $3 } else { (my $temp = ${^MATCH}) =~ s/__suffix//; $temp;} } 
  !gsepx;

  print "After:\n$_\n\n";
}

这可能效率不高,但我认为这对你的工作并不重要。

【讨论】:

  • $&amp; 与此表达式一起使用是错误的,因为它不仅匹配 cmets。
  • 我没有尝试理解表达式,我只是更改了替换部分。我猜你指的是原文所说的#defined $3 ? $3 : ""#。我去看看。谢谢。
  • $&的用处在哪里?是的,这里绝对不需要效率。
  • $&amp;${^MATCH} 相同。问题是正则表达式也匹配引号内的 cmets。我只是更改了它并更新了示例。它现在应该可以工作了。感谢您的提示,Qtax。
  • $&amp;${^MATCH} 不一样,虽然它们很相似。
【解决方案2】:

您需要分两步完成,因为您可能有

/* foo__suffix bar__suffix */

首先,提取评论,然后替换评论中的任何__suffix

s{
   \G
   (?:(?!/[*/]).)*
   \K
   (   /[*] (?:(?![*]/).)* [*]/
   |   //   [^\n]*
   )
}{
   my $comment = $1;
   $comment =~ s/(?<=\w)__suffix//g;
   $comment
}xes;

注意事项:

  • (?:(?!STRING).)(?:STRING) 就像 [^CHAR]CHAR

  • 如果您在字符串文字中有///*,我的解决方案会搞砸。

  • 如果您可以删除前面没有标识符的 __suffix 实例,则可以删除 (?&lt;=\w)

  • 如果您使用的是 5.14 或更高版本,则可以简化

    s{...}{
       my $comment = $1;
       $comment =~ s/(?<=\w)__suffix//g;
       $comment
    }xes;
    

    s{...}{
       $1 =~ s/(?<=\w)__suffix//rg
    }xes;
    

【讨论】:

  • "如果字符串文字中有 // 或 /*,我的解决方案会搞砸。"不幸的是,在这种情况下,这似乎很可能。
  • 真的吗?好吧,将(?:(?!/[*/]).)* 更改为(?: (?!/[*]|//|"). | "(?:[^"\\]|\\.)*" )* 可能会处理得很好。
  • “有点可能”可能言过其实,但“每次我说这段代码不太可能发生奇怪的情况时,我都有理由后悔”不是:) 。感谢您的更新!
猜你喜欢
  • 2010-09-19
  • 2012-07-28
  • 2013-04-12
  • 2014-05-16
  • 2011-10-27
  • 2010-10-07
  • 2018-09-06
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多