如何使用 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]匹配=].
我正在尝试修改多个文件中的几行块。最初,我尝试了 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]匹配=].