我想替換檔案中的文本并覆寫檔案。
use strict;
use warnings;
my ($str1, $str2, $i, $all_line);
$str1 = "AAA";
$str2 = "bbb";
open(RP, " >", "testfile") ;
$all_line = $_;
$i = 0;
while(<RP>) {
while(/$str1/) {
$i ;
}
s/$str1/$str2/g;
print RP $_;
}
close(RP);
uj5u.com熱心網友回復:
一個正常的程序是逐行讀取檔案并將每一行寫出,根據需要/如果需要更改,寫入一個新檔案。完成后,盡可能以原子方式重命名該新檔案,以便覆寫原始檔案。
這是一個為我們完成所有這些作業的庫的示例,Path::Tiny
use warnings;
use strict;
use feature 'say';
use Path::Tiny;
my $file = shift || die "Usage: $0 file\n";
say "File to process:";
say path($file)->slurp;
# NOTE: This CHANGES THE INPUT FILE
#
# Process each line: upper-case a letter after .
path($file)->edit_lines( sub { s/\.\s \K([a-z])/\U$1/g } );
say "File now:";
say path($file)->slurp;
這將在找到它的每一行上的一個點(句點)之后的一些空格之后大寫一個字母,并復制所有其他行不變。(這只是一個例子,不是正確的語言修復。)
注意:輸入檔案是就地編輯的,所以在完成后它會被更改。
此功能是在2016-02-10的模塊版本 0.077中引入的。(作為參考,Perl 版本 5.24 于 2016 年 8 月推出。因此,對于 Perl 5.24 或更高版本的系統,Path::Tiny從 OS 包安裝或作為默認 CPAN 版本應該具有此方法。)
uj5u.com熱心網友回復:
Perl 有一個內置的就地編輯工具:-i命令列開關。您可以通過 訪問此開關的功能$^I。
use strict;
use warnings;
my $str1 = "AAA";
my $str2 = "bbb";
local $^I = ''; # Same as `perl -i`. For `-i~`, assign `"~"`.
local @ARGV = "testfile";
while (<>) {
s/\Q$str1/$str2/g;
print;
}
uj5u.com熱心網友回復:
我不打算留下答案,但我在發表評論時發現我確實有一些反饋給你,所以就這樣吧。
open(RP, " >", "testfile") ;
該模式" >"將截斷您的檔案,洗掉所有內容。這在以下檔案中進行open了描述:
您可以在 > 或 < 前面放一個 表示您希望對檔案進行讀寫訪問;因此 < 幾乎總是首選用于讀/寫更新 - > 模式將首先破壞檔案。您通常不能使用任何一種讀寫模式來更新文本檔案,因為它們具有可變長度的記錄。請參閱 perlrun 中的 -i 開關以獲得更好的方法。
所以很自然,如果你先洗掉它的內容,你就不能從檔案中讀取。他們在這里提到了-i開關,在下面的描述中是這樣的perl -h:
-i[extension] edit <> files in place (makes backup if extension supplied)
這就是ikegami 的回答所描述的,只有在他的情況下,它是從程式檔案中完成的,而不是在命令列上完成的。
但是, 同時使用讀寫模式并不是一個好方法。基本上很難在你想列印的地方列印。推薦的方法是從一個檔案中讀取,然后列印到另一個檔案。編輯完成后,您可以根據需要重命名和洗掉檔案。這正是-i交換機為您所做的。它是 Perl 的預定義功能。在perldoc perlrun中閱讀有關它的更多資訊。
接下來,您應該使用詞法檔案句柄。例如my $fh,而不是全域。您還應該檢查 的回傳值open,以確保沒有錯誤。這給了我們:
open my $fh, "<", "testfile" or die "Cannot open 'testfile': $!";
通常如果打開失敗,你希望程式死掉,并報告它失敗的原因。錯誤在$!變數中。
另一件需要注意的是,您不應該在檔案頂部宣告所有變數。使用use strict; use warningsPerl 代碼很好,不應該在沒有它們的情況下撰寫 Perl 代碼,但這不是你處理它的方式。你宣告你的變數盡可能靠近你使用變數的地方,并且在盡可能小的范圍內。使用my宣告的變數,即最近的封閉塊{ ... }。這將使在更大的程式中跟蹤您的變數變得容易,并且它將封裝您的代碼并保護您的變數。
在您的情況下,您只需將my所有變數放在前面,如下所示:
my $str1 = "AAA";
my $str2 = "bbb";
my $all_line = $_;
my $i = 0;
請注意,那里$_將是空的/未定義的,因此分配是毫無意義的。如果您的意圖是$all_line用作回圈變數,您會這樣做:
while (my $all_line = <$fh>) {
Note that this variable is declared in the smallest scope possible, and we are using a lexical file handle $fh.
Another important note is that your replacement strings can contain regex meta characters. Sometimes you want them to be included, like for example:
my $str1 = "a "; # match one or more 'a'
Sometimes you don't want that:
my $str1 = "google.com"; # '.' is meant as a period, not the "match anything" character
I will assume that you most often do not want that, in which case you should use the escape sequence \Q ... \E which disables regex meta characters inside it.
So what do we get if we put all this together? Well, you might get something like this:
use strict;
use warnings;
my $str1 = "AAA";
my $str2 = "bbb";
my $filename = shift || "testfile"; # 'testfile', or whatever the program argument is
open my $fh_in, "<", $filename or die "Cannot open '$filename': $!";
open my $fh_out, ">", "$filename.out" or die "Cannot open '$filename.out': $!";
while (<$fh_in>) { # read from input file...
s/\Q$str1\E/$str2/g; # perform substitution...
print $fh_out $_; # print to output file
}
close $fh_in;
close $fh_out;
After this finishes, you may choose to rename the files and delete one or the other. This is basically the same procedure as using the -i switch, except here we do it explicitly.
rename $filename, "$filename.bak"; # save backup of input file in .bak extension
rename "$filename.out", $filename; # clobber the input file
Renaming files is sometimes also facilitated by the File::Copy module, which is a core module.
With all this said, you can replace all your code with this:
perl -i -pe's/AAA/bbb/g' testfile
And this is the power of the -i switch.
轉載請註明出處,本文鏈接:https://www.uj5u.com/net/427706.html
