內容

名稱

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,以取得有關封閉機制的更多詳細資訊。

use Filter::Util::Call

下列函式是由 Filter::Util::Call 匯出的

filter_add()
filter_read()
filter_read_exact()
filter_del()

import()

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()

函式 filter_add 實際上會安裝過濾器。它取一個參數,該參數應該是一個參照。所使用的參照類型將決定會使用哪兩種過濾器類型。

如果使用 CODE 參照,則會假設為封閉過濾器

如果未使用 CODE 參照,則會假設為方法過濾器。在方法過濾器中,參照可用於儲存內容資訊。除非參照已經被祝福,否則 filter_add 會將參照祝福到套件中。

請參閱此文件結尾處的過濾器,以取得使用方法過濾器封閉過濾器使用內容資訊的範例。

filter() 和匿名子程式

使用方法篩選器filter 方法和使用封閉篩選器的匿名子程式,是執行篩選器主要處理程序的位置。

這兩種篩選器類型之間的重大差異在於,方法篩選器使用傳遞給方法的物件來儲存任何內容文字資料,而封閉篩選器則使用封閉維護的詞彙變數。

請注意傳遞給方法篩選器的單一參數 $self,是傳遞給 filter_add 並已加持到篩選器套件的相同參照。有關使用 $self 的詳細資訊,請參閱稍後的範例篩選器。

以下是匿名子程式和 filter() 方法的常見功能清單。

$_

雖然 $_ 實際上並未明確出現在上述範例篩選器中,但它已在許多地方隱含使用。

首先,當呼叫 filter 或匿名子程式時,將自動建立 $_ 的本機副本。此時,它將始終包含空字串。

接下來,filter_readfilter_read_exact 都會將任何已讀取的來源資料附加到 $_ 的結尾。

最後,當 filter 或匿名子程式完成處理時,預期它們會使用 $_ 傳回已篩選的來源。

這種隱含使用 $_ 的方式大幅簡化了篩選器。

$status

使用者 filter 方法或匿名子程式傳回的狀態值,以及 filter_readread_exact 函式,採用相同的數值組,即

< 0  Error
= 0  EOF
> 0  OK
filter_readfilter_read_exact

篩選器使用這些函式從鏈中的下一個篩選器取得一行或區塊,或在沒有任何其他篩選器時取得實際的來源檔案。

函式 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_readfilter_read_exact 之後,檢查 $status 的值非常重要。

filter_del

函式 filter_del 用於停用目前的篩選器。它不會影響篩選器的執行。它所做的只是告訴 Perl 不再呼叫篩選器。

有關詳細資料,請參閱 "範例 4:使用 filter_del"

real_import

內部函式,會根據 filter_add 引數類型新增篩選器。

unimport()

可用於停用篩選器,但很少需要。請參閱 filter_del

限制

請參閱 "perlfilter 中的「限制」",以概觀僅在文字行層級中篩選程式碼的常見問題。

__DATA__ 會被忽略

__DATA__ 區塊中的內容不會被篩選。這是一個嚴重的限制,例如對於 Switch 模組。有關更多資訊,請參閱 http://search.cpan.org/perldoc?Switch#LIMITATIONS

最大程式碼大小限制為 32 位元

目前內部緩衝區長度僅限於 32 位元。

範例

以下是一些範例,說明了主要概念 - 因此,其中大多數在實務上用途不大。

examples 子目錄包含所有這些篩選器的副本,同時作為方法篩選器封閉篩選器實作。

範例 1:一個簡單的篩選器。

以下是方法篩選器,它經過硬連線,可以將字串 "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?

範例 2:使用內容

前一個範例不太實用。為了讓它更通用,我們將使用內容資料,並允許使用任何任意的來源目標字串。這次我們將使用封閉篩選器。為了反映其增強的角色,篩選器稱為 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" ;

範例 3:在過濾器中使用內容

這裡有一個過濾器,它是 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

範例 4:使用 filter_del

主題的另一種變體。這次我們將修改 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::Simple

如果您打算使用 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 本身相同的條款下重新散布或修改它。