![跨多行在两个字符串之间进行查找和替换](https://linux22.com/image/91708/%E8%B7%A8%E5%A4%9A%E8%A1%8C%E5%9C%A8%E4%B8%A4%E4%B8%AA%E5%AD%97%E7%AC%A6%E4%B8%B2%E4%B9%8B%E9%97%B4%E8%BF%9B%E8%A1%8C%E6%9F%A5%E6%89%BE%E5%92%8C%E6%9B%BF%E6%8D%A2.png)
好的,那么我需要做的就是转换这种格式的所有注释块:
/**
*
*/
到:
/*!
*/
但需要注意的是,后面的行/**
不能包含“版权”,因为我们需要保留样板许可证格式。
我觉得使用正则表达式可以很容易地做到这一点,但我对捕获组不太了解,而且因为我需要进行两次替换,所以我不知道该怎么做。我目前正在 Perl 中破解一个(糟糕的)解决方案,但我不知道如何在那里正确地进行替换。
编辑:我暂时有:\/\*\*.*(?!Copyright)^\ *(?P<ast>\*).*(?=\*\/)//sm
,它可以满足我的需要,但是如何仅替换捕获的组?
答案1
虽然复杂性未知的单个正则表达式无疑可以完成这项工作,但更容易理解和维护的可能是逐行解析器,但明显需要注意的是,这是一个糟糕的解析器,如果类似注释的字符串可能很容易被混淆出现在代码的非注释部分(CPAN 上可能有一个可用于该语言的词法分析器,或者参见解析::MGC以稍微正式的方式来做这些事情)。
#!/usr/bin/env perl
use strict;
use warnings;
my @comment;
# read stuff from standard input or files on argument line, whatever
LINE: while (<>) {
# assume this is a comment, start saving lines
if (m{^\s*/\*\*}) {
push @comment, $_;
next LINE;
}
if (@comment) {
push @comment, $_;
# here things end, or so we hope...
if (m{^\s*\*/}) {
# not copyright means fixup of the saved comment block...
if ($comment[1] !~ m/Copyright/) {
$comment[0] =~ s{/\*\*}{/*!};
if (@comment > 2) {
for my $i (1..$#comment-1) {
$comment[$i] =~ s{^(\s*)\*(\s)}{$1 $2};
}
}
}
# emit and reset
print for @comment;
@comment = ();
}
next LINE;
}
# hopefully only not-comment lines
print;
}
答案2
假设注释块并且位于行的开头(之前没有空格/**
),这样的事情可能会起作用:
#!/usr/bin/awk -f
/^\/[*][*] Copyright/ {print; next} # 1
/^\/[*][*]/ { flag = 1; sub("^/[*][*] ", "/*! ") } # 2
flag && /^ \* / { sub("^ [*]", " ") } # 3
/ [*]\// { flag = 0 } 1; # 4
(1) 如果有/** Copyright
,则打印它并转到下一行。 (2) 如果有其他/**
,设置一个标志来标记我们位于注释块中并替换为/*!
, (3) 如果设置了该标志,则从行首删除星号。 (4) 如果注释结束(*/
看到 a),则清除标志,并且1
末尾的 打印该行。
测试:
$ cat comments
/** foo
* bar
*/
* This isn't a comment
/** Copyright
* isn't changed
*/
$ awk -f strip.awk comments
/*! foo
bar
*/
* This isn't a comment
/** Copyright
* isn't changed
*/