2014-02-10 189 views
0

我正在處理腳本以在文件中執行字符串替換,我將從配置文件中讀取變量和值以及文件並進行字符串替換。PERL:文件中的字符串替換

這是我的邏輯做一個字符串替換。

sub expansion($$$){ 
my $f = shift(@_) ; # file Name 
my $vname = shift(@_) ; # variable name for pattern match 
my $value = shift(@_) ; # value to replace 
my $n = "$f".".new"; 

    open (O, "<$f") or print("Can't open $f file: $!"); 
    open (N ,">$n") or print("Can't open $n file: $!"); 
    while (<O>) 
    { 
     $_ =~ s/$vname/$value/g; #check for pattern 
     print N "$_" ; 
    } 
    close (O); 
    close (N); 


} 

在我的邏輯中,從輸入文件($ f)逐行讀取模式並寫入新文件($ n)。

而不是寫入一個新文件有沒有辦法做一個字符串替換原始文件,當我嘗試做同樣的事情,它只有空文件沒有內容。

+1

perl有一個'exp'內建函數;爲你的子選擇另一個名字。另外,不要使用原型;他們不是爲了做其他語言的原型而設計的,而且如果沒有它們,你就會變得更好。 – ysth

+0

有沒有什麼能夠防止您將新文件複製到舊文件名? – TLP

+0

我更新了函數名稱,即使在我原來的腳本中,我使用了不同的名稱..謝謝指出。 – Scg

回答

0
sub inplace_expansion($$$){ 
    my $f = shift(@_) ; # file Name 
     my $vname = shift(@_) ; # variable name for pattern match 
     my $value = shift(@_) ; # value to replace 

    local @ARGV = ($f); 
    local $^I = ''; 
    while (<>) 
    { 
     s/\Q$vname/$value/g; #check for pattern 
     print; 
    } 
} 

或者,我更傾向於將運行接近這個(基本相當,變化主要是在格式,變量名等):

use English; 
sub inplace_expansion { 
    my ($filename, $pattern, $replacement) = @_; 
    local @ARGV = ($filename), 
     $INPLACE_EDIT = ''; 
    while (<>) { 
    s/\Q$pattern/$replacement/g; 
    print; 
    } 
} 

local訣竅基本上模擬了一個命令行腳本(因爲一個人會跑perl -e);有關更多詳細信息,請參閱perldoc perlrun。有關$^I(又名$INPLACE_EDIT)的更多信息,請參閱perldoc perlvar

(對於\Q業務(在s//表達),見perldoc -f quotemeta,這是完全無關的問題,但很好的瞭解。另外要注意,在變量周圍路過的正則表達式模式—而不是,例如使用字面正則表達式專門—容易受到注入攻擊; Perl的內置taint mode在這裏很有用)

編輯:戴維W是right約原型。

1

不要。從來沒有,永遠。難道你不敢想,不要使用子程序原型。這是可怕的破碎(即,它不會做你認爲它的),並且是dangerous。現在


,我們得到了出路:

是的,你可以做你想做的。您可以使用<+模式將open文件同時讀寫。到現在爲止還挺好。

但是,由於緩衝,您不能使用標準讀取和寫入方法讀取和寫入文件。相反,您需要使用sysreadsyswrite

然後,您需要做的是讀取,使用sysseek返回到您讀取的位置,然後寫入該位置。

這樣做不但非常複雜,而且充滿了危險。我們舉一個簡單的例子。我有一個文檔,我想用直引號替換我的捲曲引號。

$line =~ s/「|」/"/g; 

這應該工作。我用另一個字符替換一個字符。有什麼可能出錯?

如果這是一個UTF-8文件(默認情況下Mac和Linux系統使用的是什麼),那些捲曲引號是雙字節字符,而直引號是單字節字符。我會寫回一條,這比我讀入的短。我的緩衝區將會關閉。

早在計算機存儲器和存儲器以千字節爲單位進行測量的時代以及串行設備如卷盤式磁帶時,這種類型的操作相當普遍。然而,在這個存儲量巨大的時代,這樣做並不值得複雜和容易出錯的過程。堅持閱讀一個文件,並寫入另一個文件。然後使用unlinkrename刪除原件並將副本重命名爲原件的名稱。

一些更多的指針:

  • 不要print如果文件無法打開。使用die。否則,您的程序將會輕輕地意識到它不能正常工作。更好的是,使用pragma use autodie;,您不必擔心測試讀取/寫入是否失敗。

  • 使用標量文件句柄。

也就是說,不是

使用

open my $out_fh, ">my_file.txt"; 
  • 而且,強烈建議使用三個參數開:

使用

open my $out_fh, ">", "my_file.txt"; 
  • 如果你不是,隨時添加use strict;use warnings;

事實上,你的Perl語法有點古老。你需要獲得一本關於Modern Perl的書。 Perl最初是作爲一種黑客語言編寫的,以取代shell和awk編程。但是,Perl已經演變成一種完整的語言,可以處理複雜的數據類型,面向對象和大型項目。學習Perl的現代語法將幫助你發現錯誤,併成爲更好的開發者。


1.像所有的規則,這可以被打破,但只有當你有一個明確和細緻的瞭解是怎麼回事。這就像那些說的節目「不要在家裏這樣做,我們是專業人士。」