如何使用 Perl 替换包含字符 '/' 和新行的多行?

How to use Perl to replace multiple lines containing character '/' and new line?

我正在尝试修改多个文件中的几行块。最初,我尝试了 sed,但读到 Perl 可能是更好的选择。但是,我的 Perl 非常基础,我不确定如何处理空(新)行和特殊字符“/”。总而言之,我想要一个像 ($perl -i -pe ...) 这样的单行代码来转换

(new line)
#include <item_b/item_bC.h>

进入

#include <item_a/item_aC.h>
#include <item_b/item_bC.h>

谢谢。

一种方法——将文件 slurp 成一个字符串,然后匹配一个可能只有空格的行,然后是一个以 #include... 开头的行,并将与该 #include 行匹配的内容替换两次

perl -0777 -wpe's{ ^\s*\n ( \#include.*\n ) }{}mxg' file.c

使用 -0777 时,它将整个文件插入 $_ 中,使用 -p 时,它在每一行打印 $_ (仅在 -0777 下打印一次,因为hte 整个文件在 $_ 所以只有一个“行”);参见 switches in perlrun/m 修饰符使 ^(和 $)也匹配(多行)字符串内的行边界。

或者,使用相同的通用方法(吞噬文件)但使用先行

perl -0777 -wpe's{ ^\s*\n (?= (\#include.*\n) ) }{}mxg' file.c

匹配一个空行,然后前瞻找到以 #include 开头的行,该行也被捕获,以便用它替换空行。由于 lookarounds 不消耗任何东西,因此无需替换该行(与其自身)。

注意,.* 是贪婪的,它会尽可能多地匹配它后面的模式,这里我们有整个文件在它前面,所以看起来 .*\n 会一直匹配到文件中的最后一个 \n!但是,. 不匹配换行符(使用 /s 修饰符)所以 .*\n 在这里停在第一个换行符处,因此它匹配该行的其余部分。

如果需要匹配更具体的包含语句,请在 #include 模式后添加详细信息。

否则,可以逐行处理,方法是复制当前行并在下一行打印它,具体取决于保存的内容和下一行。那里有一些挑剔的细节需要拉直,不太适合单行。

均使用输入 file.c 进行了测试(注意:它确实以空行开头)

    
#include<item_b/item_bC.h>
#include<item_a/item_aC.h>

#include<item_c/item_cC.h>

int main() {

    return 1;
}

我们最终得到两个 item_b 和一个 item_a 以及两个 itewm_c 包含并且没有空行,文件的其余部分不受影响。


提到了特殊字符所以我会评论。但请查阅更完整的资源,例如教程 perlretut and reference perlre. See also perlrebackslash

当使用 \ 转义时,正则表达式的特殊字符大部分可以作为模式中的文字字符进行匹配。但在这种情况下不需要:/ 在正则表达式中的作用只是分隔模式,通常给出 /.../,但这里我使用 {}{} 作为分隔符;所以 / 在这里并不特殊,可以自由使用。例如

perl -0777 -wpe's{ ^\s*\n (?= (\#include<item_./.*\n) ) }{}mxg' file.c

匹配我使用的输入文件中的行,如上所示。

在实际问题中显然有一个更通用的模式而不是item,它是一个文件名。文件名中允许的大多数字符都可以在正则表达式中按字面意思使用。可以转义异常,例如 .,例如 \. 以匹配文字 ..

例如字符串item_bC.h,其中bC个字符不同,但item.h始终相同,可以用模式[=49]匹配=].