Filter::Util::Call - Perl 原始碼過濾器公用程式模組
use Filter::Util::Call ;
此模組提供架構,讓您能使用 Perl 撰寫「原始碼過濾器」。
現在提供 Filter::Util::Call 的替代介面。請參閱 Filter::Simple 以取得更多詳細資訊。
「Perl 原始碼過濾器」實作為 Perl 模組。模組的結構可採用兩種大致類似的格式。為了區分它們,第一種將稱為「方法過濾器」,第二種稱為「封閉過濾器」。
以下是「方法過濾器」的範本
package MyFilter ;
use Filter::Util::Call ;
sub import
{
my($type, @arguments) = @_ ;
filter_add([]) ;
}
sub filter
{
my($self) = @_ ;
my($status) ;
$status = filter_read() ;
$status ;
}
1 ;
而這是封閉過濾器的等效骨架
package MyFilter ;
use Filter::Util::Call ;
sub import
{
my($type, @arguments) = @_ ;
filter_add(
sub
{
my($status) ;
$status = filter_read() ;
$status ;
} )
}
1 ;
若要使用上述兩個過濾器模組中的任一個,請將以下程式碼行置於 Perl 原始檔中。
use MyFilter;
事實上,上述顯示的骨架模組是功能齊全的原始檔過濾器,儘管相當無用。它們所做的只是過濾原始檔串流,而完全不修改它。
如你所見,兩個模組都有大致相似的結構。它們都使用 Filter::Util::Call
模組,且都有 import
方法。它們之間的差異在於方法過濾器需要一個過濾器方法,而封閉過濾器則透過傳遞給 filter_add 的匿名子程式取得等效的過濾器方法。
若要適當使用上述顯示的封閉過濾器,你需要充分了解封閉的概念。請參閱 perlref,以取得有關封閉機制的更多詳細資訊。
下列函式是由 Filter::Util::Call
匯出的
filter_add()
filter_read()
filter_read_exact()
filter_del()
import
方法用於建立過濾器的執行個體。當 Perl 在原始檔中遇到 use MyFilter
程式碼行時,會間接呼叫它(請參閱 "import" in perlfunc,以取得有關 import
的更多詳細資訊)。
它至少會有一個由 Perl 自動傳遞的參數 - 這對應於套件的名稱。在上述範例中,它會是 "MyFilter"
。
除了第一個參數之外,import 可以接受一個選用參數清單。這些參數可用於傳遞參數給過濾器。例如
use MyFilter qw(a b c) ;
將導致 @_
陣列具有下列值
@_ [0] => "MyFilter"
@_ [1] => "a"
@_ [2] => "b"
@_ [3] => "c"
在終止之前,import
函式必須透過呼叫 filter_add
明確安裝過濾器。
函式 filter_add
實際上會安裝過濾器。它取一個參數,該參數應該是一個參照。所使用的參照類型將決定會使用哪兩種過濾器類型。
如果使用 CODE 參照,則會假設為封閉過濾器。
如果未使用 CODE 參照,則會假設為方法過濾器。在方法過濾器中,參照可用於儲存內容資訊。除非參照已經被祝福,否則 filter_add
會將參照祝福到套件中。
請參閱此文件結尾處的過濾器,以取得使用方法過濾器和封閉過濾器使用內容資訊的範例。
使用方法篩選器的 filter
方法和使用封閉篩選器的匿名子程式,是執行篩選器主要處理程序的位置。
這兩種篩選器類型之間的重大差異在於,方法篩選器使用傳遞給方法的物件來儲存任何內容文字資料,而封閉篩選器則使用封閉維護的詞彙變數。
請注意傳遞給方法篩選器的單一參數 $self
,是傳遞給 filter_add
並已加持到篩選器套件的相同參照。有關使用 $self
的詳細資訊,請參閱稍後的範例篩選器。
以下是匿名子程式和 filter()
方法的常見功能清單。
雖然 $_
實際上並未明確出現在上述範例篩選器中,但它已在許多地方隱含使用。
首先,當呼叫 filter
或匿名子程式時,將自動建立 $_
的本機副本。此時,它將始終包含空字串。
接下來,filter_read
和 filter_read_exact
都會將任何已讀取的來源資料附加到 $_
的結尾。
最後,當 filter
或匿名子程式完成處理時,預期它們會使用 $_
傳回已篩選的來源。
這種隱含使用 $_
的方式大幅簡化了篩選器。
使用者 filter
方法或匿名子程式傳回的狀態值,以及 filter_read
和 read_exact
函式,採用相同的數值組,即
< 0 Error
= 0 EOF
> 0 OK
篩選器使用這些函式從鏈中的下一個篩選器取得一行或區塊,或在沒有任何其他篩選器時取得實際的來源檔案。
函式 filter_read
採用兩種形式
$status = filter_read() ;
$status = filter_read($size) ;
第一種形式用於要求一行,第二種形式要求一個區塊。
在行模式中,filter_read
會將下一個來源行附加到 $_
純量的結尾。
在區塊模式中,filter_read
會將資料區塊(<= $size
)附加到 $_
純量的結尾。重要的是要強調,filter_read
不一定會讀取大小精確為 $size
位元的組塊。
如果您需要能夠讀取大小精確的區塊,可以使用函式 filter_read_exact
。它的運作方式與區塊模式中的 filter_read
相同,但它會嘗試讀取大小精確為 $size
位元的區塊。它不會傳回大小為 $size
位元的區塊的唯一情況是在 EOF 或錯誤時。
在每次呼叫 filter_read
或 filter_read_exact
之後,檢查 $status
的值非常重要。
函式 filter_del
用於停用目前的篩選器。它不會影響篩選器的執行。它所做的只是告訴 Perl 不再呼叫篩選器。
有關詳細資料,請參閱 "範例 4:使用 filter_del"。
內部函式,會根據 filter_add 引數類型新增篩選器。
可用於停用篩選器,但很少需要。請參閱 filter_del。
請參閱 "perlfilter 中的「限制」",以概觀僅在文字行層級中篩選程式碼的常見問題。
__DATA__ 區塊中的內容不會被篩選。這是一個嚴重的限制,例如對於 Switch 模組。有關更多資訊,請參閱 http://search.cpan.org/perldoc?Switch#LIMITATIONS。
目前內部緩衝區長度僅限於 32 位元。
以下是一些範例,說明了主要概念 - 因此,其中大多數在實務上用途不大。
examples
子目錄包含所有這些篩選器的副本,同時作為方法篩選器和封閉篩選器實作。
以下是方法篩選器,它經過硬連線,可以將字串 "Joe"
的所有出現位置替換為 "Jim"
。不太實用,但這是第一個範例,我希望讓它保持簡單。
package Joe2Jim ;
use Filter::Util::Call ;
sub import
{
my($type) = @_ ;
filter_add(bless []) ;
}
sub filter
{
my($self) = @_ ;
my($status) ;
s/Joe/Jim/g
if ($status = filter_read()) > 0 ;
$status ;
}
1 ;
以下是使用篩選器的範例
use Joe2Jim ;
print "Where is Joe?\n" ;
以下是上述指令碼會印出的內容
Where is Jim?
前一個範例不太實用。為了讓它更通用,我們將使用內容資料,並允許使用任何任意的來源和目標字串。這次我們將使用封閉篩選器。為了反映其增強的角色,篩選器稱為 Subst
。
package Subst ;
use Filter::Util::Call ;
use Carp ;
sub import
{
croak("usage: use Subst qw(from to)")
unless @_ == 3 ;
my ($self, $from, $to) = @_ ;
filter_add(
sub
{
my ($status) ;
s/$from/$to/
if ($status = filter_read()) > 0 ;
$status ;
})
}
1 ;
並像這樣使用
use Subst qw(Joe Jim) ;
print "Where is Joe?\n" ;
這裡有一個過濾器,它是 Joe2Jim
過濾器的變體。它除了將所有 "Joe"
替換為 "Jim"
之外,還會在內容物件中記錄替換次數。
一旦偵測到 EOF($status
為零),過濾器就會在來源串流中插入額外一行。執行這額外一行時,它會列印實際替換的次數。請注意,$status
在這種情況下會設定為 1
。
package Count ;
use Filter::Util::Call ;
sub filter
{
my ($self) = @_ ;
my ($status) ;
if (($status = filter_read()) > 0 ) {
s/Joe/Jim/g ;
++ $$self ;
}
elsif ($$self >= 0) { # EOF
$_ = "print q[Made ${$self} substitutions\n]" ;
$status = 1 ;
$$self = -1 ;
}
$status ;
}
sub import
{
my ($self) = @_ ;
my ($count) = 0 ;
filter_add(\$count) ;
}
1 ;
以下是使用它的腳本
use Count ;
print "Hello Joe\n" ;
print "Where is Joe\n" ;
輸出
Hello Jim
Where is Jim
Made 2 substitutions
主題的另一種變體。這次我們將修改 Subst
過濾器,以允許指定開始和停止模式,以及 從 和 到 模式。如果您知道 vi 編輯器,它等於這個指令
:/start/,/stop/s/from/to/
當用作過濾器時,我們想要這樣呼叫它
use NewSubst qw(start stop from to) ;
以下是模組。
package NewSubst ;
use Filter::Util::Call ;
use Carp ;
sub import
{
my ($self, $start, $stop, $from, $to) = @_ ;
my ($found) = 0 ;
croak("usage: use Subst qw(start stop from to)")
unless @_ == 5 ;
filter_add(
sub
{
my ($status) ;
if (($status = filter_read()) > 0) {
$found = 1
if $found == 0 and /$start/ ;
if ($found) {
s/$from/$to/ ;
filter_del() if /$stop/ ;
}
}
$status ;
} )
}
1 ;
如果您打算使用 Filter::Call 功能,我強烈建議您查看 Damian Conway 出色的 Filter::Simple 模組。Damian 的模組提供了比 Filter::Util::Call 更簡潔的介面。雖然它不允許 Filter::Util::Call 進行的精細控制,但它應該足以應付大多數應用程式。它可以在這裡取得
http://search.cpan.org/dist/Filter-Simple/
Paul Marquess
1996 年 1 月 26 日
版權所有 (c) 1995-2011 Paul Marquess。保留所有權利。版權所有 (c) 2011-2014、2018-2022 Reini Urban。保留所有權利。版權所有 (c) 2014-2017 cPanel Inc。保留所有權利。
這個程式是自由軟體;您可以在與 Perl 本身相同的條款下重新散布或修改它。