读取一个文件并修改它
Read a file and modify it
我正在尝试处理数据流。
首先我将一个文本文件添加到我的脚本中。
文本文件是这样的:
pierwsza linia koniec
druga linia lorem1 koniec lorem1 lorem1
trzecia linia lorem1 koniec lorem1
czwarta linia lorem1 koniec
piata liniakoniec
szosta linia lorem1 koniec
我想要实现的是一个包含所有行但只有第一次出现 lorem1
.
的文件
所以预期的结果应该是这样的
pierwsza linia koniec
druga linia lorem1 koniec
trzecia linia koniec
czwarta linia koniec
piata liniakoniec
szosta linia koniec
我的脚本是这样的
#!/usr/bin/perl -pi
use strict;
my $line = $_;
my $loremcn;
while ( $line = <> ) {
#if ( $line =~ m/lorem1/ )
foreach ( $line =~ m/lorem1/gi ) {
$loremcn++;
if ( $loremcn >= 2 ) {
$line =~ s/lorem1//gi;
}
print "$loremcn\n";
print $line;
chomp $line;
}
}
但是结果只是文本的第一行(因为脚本开头的 -pi
)。
该脚本正确计算了 lorem1
(7) 的出现次数,但由于 /g
选项,它删除了所有 lorem1
的出现次数(它不会单独留下第一个)。
最后,最后如何将整条更正后的文字打印到屏幕上?
更新
我对其中一个答案写了这条重要评论:
In RL I cannot do this Your way. This whole excercise is to find a way on how to do this with streamed data. In true scenario the whole data is not from opened text, but it's a spool data streamed to printer from SAP. And that data needs to be corrected on the way to the printer
#!/usr/bin/perl
use strict;
use warnings;
# lorem counter
my $loremcn = 0;
# loop over the input file
while (my $line = <> ) {
# if line contains lorem1 but not alorem1 or lorem12
if ($line =~ /\blorem1\b/i) {
# not the first time. counter > 0
if ($loremcn) {
# remove all lorem1 and optional leading horizontal spaces
$line =~ s/\h*\blorem1\b//gi; # comment for syntax color /
# first time lorem1 is encountered (counter == 0)
} else {
# remove all lorem1 but the first
while ($line =~ s/
(\blorem1\b.*?) # first lorem1 in the line followed by 0 or more anycharacter
\blorem1\b # subsequent lorem1
//gix # replace with the first group (i.e. the first lorem1
) { 1;}
}
# incement counter
$loremcn++;
}
# print the modified line
print $line;
}
输出:
pierwsza linia koniec
druga linia lorem1 koniec
trzecia linia koniec
czwarta linia koniec
piata liniakoniec
szosta linia koniec
用法:
perl test.pl inputfile > outputfile
不就是这个吗?
my $seen;
while (<>) {
s/\blorem1\b//g if $seen;
$seen = 1 if /\blorem1\b/;
print;
}
更新: 好吧,比我原先想象的要复杂一点。但这似乎可以满足您的要求:
#!/usr/bin/perl
use strict;
use warnings;
my $seen;
while (<>) {
if ($seen) {
s/\blorem1\b//g;
} else {
1 while s/(?<=\blorem1\b)(.*)\blorem1\b//g;
$seen = 1 if /\blorem1\b/;
}
print;
}
运行 你的代码 B::Deparse
像这样
perl -MO=Deparse xx.pl
给出这个结果
BEGIN { $^I = ""; } # From -i
LINE: while (defined($_ = readline ARGV)) {
use strict;
my $line = $_;
my $loremcn;
while (defined($line = readline ARGV)) {
foreach $_ ($line =~ /lorem1/gi) {
++$loremcn;
if ($loremcn >= 2) {
$line =~ s/lorem1//gi;
}
print "$loremcn\n";
print $line;
chomp $line;
}
}
}
continue {
die "-p destination: $!\n" unless print $_;
}
所以您看到您的代码中有 两个 while
循环:您不应该将命令行选项与程序文件混淆,因此可能不明显
这是一种实现我认为您想要的方法。它使用你的全局计数器 $loremcn
和一个 表达式 全局替换来替换 lorem1
在第一个实例
之后什么都没有
#!/usr/bin/perl
use strict;
use warnings 'all';
@ARGV = 'file1.txt';
my $loremcn = 0;
while ( <> ) {
s{(\blorem1\b[ \t]*)}{ $loremcn++ ? '' : }ge;
print;
}
输出
pierwsza linia koniec
druga linia lorem1 koniec
trzecia linia koniec
czwarta linia koniec
piata liniakoniec
szosta linia koniec
一个衬垫使用 perl
:
您可以保留第一个 lorem 之前的所有内容,然后删除此之后的所有 lorem,即
$perl -pe "undef $/;s/^.*?\blorem1\K|\blorem1//g" lorem.txt
\b
- 用于确定边界。
.*?
- 非贪婪匹配。将所有内容都匹配到第二个 lorem
\K
- 丢弃任何之前消耗的字符。因此从第二个lorem删除到最后
输出
pierwsza linia koniec
druga linia lorem1 koniec
trzecia linia koniec
czwarta linia koniec
piata liniakoniec
szosta linia koniec
现在如果你想把它保存在另一个文件中,你可以这样做:
perl -pe "undef $/;s/^.*?\blorem1\K|\blorem1//g" lorem.txt > new_file.txt
如果你的perl
版本不支持\K
,你可以使用:
perl -pe "undef $/;s/(^.*?\blorem1)|\blorem1//g" lorem.txt
我正在尝试处理数据流。
首先我将一个文本文件添加到我的脚本中。
文本文件是这样的:
pierwsza linia koniec
druga linia lorem1 koniec lorem1 lorem1
trzecia linia lorem1 koniec lorem1
czwarta linia lorem1 koniec
piata liniakoniec
szosta linia lorem1 koniec
我想要实现的是一个包含所有行但只有第一次出现 lorem1
.
所以预期的结果应该是这样的
pierwsza linia koniec
druga linia lorem1 koniec
trzecia linia koniec
czwarta linia koniec
piata liniakoniec
szosta linia koniec
我的脚本是这样的
#!/usr/bin/perl -pi
use strict;
my $line = $_;
my $loremcn;
while ( $line = <> ) {
#if ( $line =~ m/lorem1/ )
foreach ( $line =~ m/lorem1/gi ) {
$loremcn++;
if ( $loremcn >= 2 ) {
$line =~ s/lorem1//gi;
}
print "$loremcn\n";
print $line;
chomp $line;
}
}
但是结果只是文本的第一行(因为脚本开头的 -pi
)。
该脚本正确计算了 lorem1
(7) 的出现次数,但由于 /g
选项,它删除了所有 lorem1
的出现次数(它不会单独留下第一个)。
最后,最后如何将整条更正后的文字打印到屏幕上?
更新
我对其中一个答案写了这条重要评论:
In RL I cannot do this Your way. This whole excercise is to find a way on how to do this with streamed data. In true scenario the whole data is not from opened text, but it's a spool data streamed to printer from SAP. And that data needs to be corrected on the way to the printer
#!/usr/bin/perl
use strict;
use warnings;
# lorem counter
my $loremcn = 0;
# loop over the input file
while (my $line = <> ) {
# if line contains lorem1 but not alorem1 or lorem12
if ($line =~ /\blorem1\b/i) {
# not the first time. counter > 0
if ($loremcn) {
# remove all lorem1 and optional leading horizontal spaces
$line =~ s/\h*\blorem1\b//gi; # comment for syntax color /
# first time lorem1 is encountered (counter == 0)
} else {
# remove all lorem1 but the first
while ($line =~ s/
(\blorem1\b.*?) # first lorem1 in the line followed by 0 or more anycharacter
\blorem1\b # subsequent lorem1
//gix # replace with the first group (i.e. the first lorem1
) { 1;}
}
# incement counter
$loremcn++;
}
# print the modified line
print $line;
}
输出:
pierwsza linia koniec
druga linia lorem1 koniec
trzecia linia koniec
czwarta linia koniec
piata liniakoniec
szosta linia koniec
用法:
perl test.pl inputfile > outputfile
不就是这个吗?
my $seen;
while (<>) {
s/\blorem1\b//g if $seen;
$seen = 1 if /\blorem1\b/;
print;
}
更新: 好吧,比我原先想象的要复杂一点。但这似乎可以满足您的要求:
#!/usr/bin/perl
use strict;
use warnings;
my $seen;
while (<>) {
if ($seen) {
s/\blorem1\b//g;
} else {
1 while s/(?<=\blorem1\b)(.*)\blorem1\b//g;
$seen = 1 if /\blorem1\b/;
}
print;
}
运行 你的代码 B::Deparse
像这样
perl -MO=Deparse xx.pl
给出这个结果
BEGIN { $^I = ""; } # From -i
LINE: while (defined($_ = readline ARGV)) {
use strict;
my $line = $_;
my $loremcn;
while (defined($line = readline ARGV)) {
foreach $_ ($line =~ /lorem1/gi) {
++$loremcn;
if ($loremcn >= 2) {
$line =~ s/lorem1//gi;
}
print "$loremcn\n";
print $line;
chomp $line;
}
}
}
continue {
die "-p destination: $!\n" unless print $_;
}
所以您看到您的代码中有 两个 while
循环:您不应该将命令行选项与程序文件混淆,因此可能不明显
这是一种实现我认为您想要的方法。它使用你的全局计数器 $loremcn
和一个 表达式 全局替换来替换 lorem1
在第一个实例
#!/usr/bin/perl
use strict;
use warnings 'all';
@ARGV = 'file1.txt';
my $loremcn = 0;
while ( <> ) {
s{(\blorem1\b[ \t]*)}{ $loremcn++ ? '' : }ge;
print;
}
输出
pierwsza linia koniec
druga linia lorem1 koniec
trzecia linia koniec
czwarta linia koniec
piata liniakoniec
szosta linia koniec
一个衬垫使用 perl
:
您可以保留第一个 lorem 之前的所有内容,然后删除此之后的所有 lorem,即
$perl -pe "undef $/;s/^.*?\blorem1\K|\blorem1//g" lorem.txt
\b
- 用于确定边界。.*?
- 非贪婪匹配。将所有内容都匹配到第二个lorem
\K
- 丢弃任何之前消耗的字符。因此从第二个lorem删除到最后
输出
pierwsza linia koniec
druga linia lorem1 koniec
trzecia linia koniec
czwarta linia koniec
piata liniakoniec
szosta linia koniec
现在如果你想把它保存在另一个文件中,你可以这样做:
perl -pe "undef $/;s/^.*?\blorem1\K|\blorem1//g" lorem.txt > new_file.txt
如果你的perl
版本不支持\K
,你可以使用:
perl -pe "undef $/;s/(^.*?\blorem1)|\blorem1//g" lorem.txt