Perl - 如何从文本文件中省略行?
Perl - How to omit lines from a text file?
我有一个文本文件,我想从文本文件中省略一些行,并使用该字符串创建一个新文件。好消息是我的文本文件以包含“START”并以“END”结尾的行开始我需要的文本块。
例如,我的文本文件如下所示:
1
2
3
Start
4
5
6
End
7
8
Start
9
10
End
所需的输出将是两个字符串,我可以将它们输出到如下所示的文本文件中:
Start
4
5
6
End
Start
9
10
End
我目前拥有的:
open(RH, '<', $fileName) or die $!;
while(<RH>) {
#print $_;
chomp $_;
if ($_ eq 'START') {
$str = "$str"."$_\n";
}
}
但我不确定如何继续。
编辑:
我使用以下方法回答了这个问题:
$cmd = q(awk '/Start/,/End/ {print}' foo.txt);
my $output = qx($cmd);
my @cards = split (/(?<=\End)/, $output);
您可以使用 AWK 中的一些 Perl 遗产并执行此操作(假设您的文件名为 foo.txt)
perl -ne'print if /Start/../End/' foo.txt
表达式 /Start/../End/
表示“从匹配 /Start/
的第一行到匹配 /End/
.
的下一行
awk 的等效代码是
awk '/Start/,/End/ {print}' foo.txt
# Read the entire file into a string `$str`:
open my $fh, '<', 'file_name' or die "Can't open file $!";
my $str = do { local $/; <$fh> };
close $fh;
while ($str =~ m{\n(START\n.*\nEND)\n}msg) {
# Do something with each START...END set of lines
print "$str\n";
}
备注:
- 我不确定所有细节。
local $/
;可以通过类似 undef $/;
的方式完成
- 调整括号以避免捕获 'START' 和 'END'。
使用 GNU grep
:
grep -Poz '(?ms)^Start.*?^End\n' in_file
此处,GNU grep
使用以下选项:
-P
: 使用 Perl 正则表达式。
-o
:仅打印匹配项(每行 1 个匹配项),而不是整行。
-z
:将输入和输出数据视为行序列,每行以零字节(ASCII NUL 字符)而不是换行符终止。因此,您可以匹配输入中的换行符。
(?ms)
:启用m
和s
pattern-match modifiers,分别允许多行匹配,允许.
匹配换行。
将..
用作“触发器”运算符。
# Switch to a lexical filehandle
# (as this is modern best practice)
open(my $rh, '<', $fileName) or die $!;
# Open an output filehandle
my $x = 1;
open my $out, '>', "$filename.out.$x" or die $!;
while(<$rh>) {
print $out $_ if /Start/ .. /End/;
# Open a new output file if we've seen 'End'
if (/End/) {
++$x;
open my $out, '>', "$filename.out.$x" or die $!;
}
}
我有一个文本文件,我想从文本文件中省略一些行,并使用该字符串创建一个新文件。好消息是我的文本文件以包含“START”并以“END”结尾的行开始我需要的文本块。
例如,我的文本文件如下所示:
1
2
3
Start
4
5
6
End
7
8
Start
9
10
End
所需的输出将是两个字符串,我可以将它们输出到如下所示的文本文件中:
Start
4
5
6
End
Start
9
10
End
我目前拥有的:
open(RH, '<', $fileName) or die $!;
while(<RH>) {
#print $_;
chomp $_;
if ($_ eq 'START') {
$str = "$str"."$_\n";
}
}
但我不确定如何继续。
编辑: 我使用以下方法回答了这个问题:
$cmd = q(awk '/Start/,/End/ {print}' foo.txt);
my $output = qx($cmd);
my @cards = split (/(?<=\End)/, $output);
您可以使用 AWK 中的一些 Perl 遗产并执行此操作(假设您的文件名为 foo.txt)
perl -ne'print if /Start/../End/' foo.txt
表达式 /Start/../End/
表示“从匹配 /Start/
的第一行到匹配 /End/
.
awk 的等效代码是
awk '/Start/,/End/ {print}' foo.txt
# Read the entire file into a string `$str`:
open my $fh, '<', 'file_name' or die "Can't open file $!";
my $str = do { local $/; <$fh> };
close $fh;
while ($str =~ m{\n(START\n.*\nEND)\n}msg) {
# Do something with each START...END set of lines
print "$str\n";
}
备注:
- 我不确定所有细节。
local $/
;可以通过类似undef $/;
的方式完成
- 调整括号以避免捕获 'START' 和 'END'。
使用 GNU grep
:
grep -Poz '(?ms)^Start.*?^End\n' in_file
此处,GNU grep
使用以下选项:
-P
: 使用 Perl 正则表达式。
-o
:仅打印匹配项(每行 1 个匹配项),而不是整行。
-z
:将输入和输出数据视为行序列,每行以零字节(ASCII NUL 字符)而不是换行符终止。因此,您可以匹配输入中的换行符。
(?ms)
:启用m
和s
pattern-match modifiers,分别允许多行匹配,允许.
匹配换行。
将..
用作“触发器”运算符。
# Switch to a lexical filehandle
# (as this is modern best practice)
open(my $rh, '<', $fileName) or die $!;
# Open an output filehandle
my $x = 1;
open my $out, '>', "$filename.out.$x" or die $!;
while(<$rh>) {
print $out $_ if /Start/ .. /End/;
# Open a new output file if we've seen 'End'
if (/End/) {
++$x;
open my $out, '>', "$filename.out.$x" or die $!;
}
}