国产一级a片免费看高清,亚洲熟女中文字幕在线视频,黄三级高清在线播放,免费黄色视频在线看

打開APP
userphoto
未登錄

開通VIP,暢享免費電子書等14項超值服

開通VIP
perl的特殊變量 - Perl - ChinaUnix.net
讓你的perl代碼看起來更像perl代碼,而不是像C或者BASIC代碼,最好的辦法就是去了解perl的內置變量。perl可以通過這些內置變量可以控制程序運行時的諸多方面。
本文中,我們一起領略一下眾多內置變量在文件的輸入輸出控制上的出色表現。

行計數
我決定寫這篇文章的一個原因就是,當我發(fā)現很多人都不知道“$.”內置變量的存在,這的確讓我很吃驚。
我依然能看到很多人是這樣寫代碼的:
代碼


    my $line_no = 0;

    while (<FILE>) {
    ++$line_no;
    unless (/some regex/) {
     warn "Error in line $line_no\n";
     next;
    }

    # process the record in some way
    }



由于某些原因,很多人似乎完全忽略了“$.”的存在。而這個變量的作用就是跟蹤當前記錄號。因此上面的代碼也可以這樣來寫:
代碼


    while (<FILE>)

    {
    unless (/some regex/) {
     warn "Error in line $.\n";
     next;
    }

    # process the record in some way
    }




譯者注:通俗的說,這個內置變量就跟數據庫中的記錄指針非常相似,它的值就是你當前所讀文件中的當前行號。

雖然使用此內置變量并不能讓你少打多少字,但重要的是我們可以省去一些不必要的變量聲明。
另一種利用此內置變量的方法就是與連續(xù)操作符(..)一起使用。當用在列表上下文中時,(..)是列表構建操作符。它將從給出的開始和結束元素之間創(chuàng)建所有的元素。例如:
代碼


    my @numbers = (1 .. 1000);


@numbers將包含從1到1000之間所有的整數。


但是當你在一個表達式上下文中使用此操作符時(比如,作為一個聲明的條件),它的作用就完全不一樣了。第一個操作數(“..“左側的表達式)將被求值,如果得出的值為假,此次操作將什么也不做并返回假值。如果得出的值為真,操作返回真值并繼續(xù)依次返回下面的值直到第二個操作數(“..”操作符右面的表達式)返回真值。
我們舉個例子解釋一下。假設你有一個文件,你只想處理這個文件的某幾個部分。這幾個部分以"!! START !!"為開始,"!! END !!"為結束。
使用連續(xù)操作符你可以這樣寫這段代碼:
代碼


    while (<FILE>) {
    if (/!! START !!/ .. /!! END !!/) {
     # process line
    }
    }




每一次循環(huán),連續(xù)操作符就會檢查當前行。如果當前行與“/!! START !!/”不匹配,則操作符返回假值并繼續(xù)循環(huán)。當循環(huán)到第一個與/!! START !!/”相匹配的行時,連續(xù)操作符就會返回真值并執(zhí)行if語句塊中的代碼。在while語句后面的循環(huán)中,連續(xù)操作符將再次檢查“/!! END !!/”的匹配行,但是它直到找到匹配行后才會返回真值。這也就是說在"!! START !!" 和"!! END !!" 標記之間的所有行都將被處理。當找到/!! END !!/的匹配行后,連續(xù)操作符返回假并再次開始匹配第一個規(guī)則表達式。

這些與“$.”有什么關系呢?如果連續(xù)操作符的操作數有一個是常量的話,他們將被轉化為整型數并于“$.”匹配。
因此輸出一個文件的前10行內容我們可以這樣寫代碼:
代碼


    while (<FILE>) {
    print if 1 .. 10;
    }



關于“$.”最后要說明的一點是,一個程序中只有一個“$.”變量。如果你在從多個文件句柄中讀數據,那么“$.”變量保存了最近讀過的文件句柄中的當前記錄號。如果你想要更復雜的解決此問題的方法那么你可以使用類似IO::FILE對象。這些對象都有一個input_line_number方法。

記錄分隔符

“$/” 和 “$\”分別是輸入輸出記錄分隔符。當你在讀或者寫數據時,他們主要控制用什么來定義一個“記錄”。

讓我更詳細地給大家解釋一下吧。當你第一次學習perl,第一次知道文件輸入操作符的時候,也許你會被告知“<FILE>”就是從一個文件讀
入一行數據,而讀入的每一行都包括一個新行字符(“\n”)。其實你所知道的這些并不完全是真的,那只是一個很特殊的情況。實際上文件輸入操作符(“<>”)讀數據后會包含一個在“$/”中指定的文件輸入分隔符。讓我們來看一個例子:

假設你有一個文本文件,內容是些有趣的引文或者一些歌詞或者一些別的什么東西。比如類似下面的內容:
代碼


    This is the definition of my life
    %%
    We are far too young and clever
    %%
    Stab a sorry heart
    With your favorite finger



在這里有三段被一行“%%”分隔的引文。那么我們該如何從這個文件中一次讀取一段引文呢。(譯者注:這一段引文可是一行也可以是幾行,比如例子中的第一段和第二段引文都是一行,而第三段引文是2行)
其中一個解決方法就是,一次從文件中讀取一行,然后檢查讀入的行是否是“%%”。因此我們需要聲明一個變量用來保存每次讀入的數據,當遇到“%%”后重新組合先前讀入的數據為一段完整的引文。哦,你還需要記得處理最后一段引文因為它最后沒有“%%”。
這樣的方法太過于復雜,一個簡單的方法就是更改“$/”變量的內容。該變量的默認值是一個新行字符(“\n”),這也就是為什么“<>”
操作符在讀取文件內容時是一次讀一行。但是我們可以修改這一變量內容為我們喜歡的任意值。比如:

代碼


    $/ = "%%\n";

    while (<QUOTE>) {
    chomp;
    print;
    }



現在我們每次調用“<>”,perl會從文件句柄中一次讀取數據直到發(fā)現 “%%\n”為止。(不是一次讀一行了)。
因此,當你用chomp函數來去掉讀取數據的行分隔符時,就會刪除“$/”變量中指定的分隔符了。在上例中經過chomp函數處理后的數據都會將
%%\n”刪除。

更改perl的特殊變量

在我們繼續(xù)之前,我需要提醒你的是,當你修改了這些特殊變量的值后,你會得到一個警告。問題就是這些變量中的多數是被強制在主包中
的。也就是說當你更改這些變量的值時,程序中用到這個值的地方(包括你包含的那些模塊)都會給出警告。
比如如果你在寫一個模塊,且你在模塊中更改了“$/”變量的值,那么當別人把你的模塊應用到自己的程序中時就必須相應的修改其他模塊
以適應程序的執(zhí)行。所以修改特殊變量的值潛在地增加了查找bugs的難度。

因此我們應該盡可能的避免它。第一個避免的方法是在你用完了修改后的特殊變量的值后應該將該特殊變量重值回原始值。比如:
代碼


    $/ = "%%\n";

    while (<QUOTE>) {
    chomp;
    print;
    }

    $/ = "\n";



而這個方法引發(fā)的另一個問題就是你不能確定在你重置特殊變量的值之前它的值就是系統(tǒng)默認值。
(譯者注:比如如果你在“$/ = "%%\n";”之前就修改過“$/”變量的值(不是默認值“\n”),那么你最后重置回默認值肯定會引發(fā)錯誤的)
因此我們的代碼應該像如下才對,如下:
代碼


    $old_input_rec_sep = $/;
    $/ = "%%\n";

    while (<QUOTE>) {
    chomp;
    print;
    }

    $/ = $old_input_rec_sep;




上面的代碼就避免了我們上述所說的bug,但是我們有另一個看起來更簡練的方法。這個方法就是使用local來定義“$/”變量。如下:
代碼


    {
    local $/ = "%%\n";

    while (<QUOTE>) {
     chomp;
     print;
    }
    }



我們將代碼以一對大括號括起來。一般的,代碼塊往往與循環(huán),條件或者是子程序有關聯(lián),但是在perl中是可以單獨用大括號來說明一個代碼塊的。
而在這個代碼塊內用local定義的變量只在當前代碼塊中起作用。
綜上所述,不更改perl的內置變量是一個很好的習慣,除非它被本地化在一個代碼塊中。


“$/”的其他值

下面給出一些你可以賦予“$/”變量的特殊值,這些值可以開啟一些有趣的行為。第一個就是設置該變量為未定義。這將開啟slurp模式,
開啟該模式后我們可以一次性從一個文件中讀取全部的文件內容。如下:
代碼


    my $file = do { local $/; <FILE> };



一個do語句塊的返回值是語句塊中最后一個表達式的值,如上面的do語句塊的返回值就是“<>”操作符的返回值。而且由于“$/”變量被設置為 undef(未定義),所以返回的就是整個文件的內容。需要注意的是,我們不需要明確地指定“$/”變量為undef,因為所有的perl變量在定義的時候就被自動初始化為undef。

設置“$/”變量為undef和空值是有很大區(qū)別的:設置成空值意味著開啟paragraph模式(即段落模式),在這種模式下,每個記錄就是一段以一個或更多空行為結束的文本段落。也許你會認為這種效果和把“$/”變量被設置為“\n\n”的效果是一樣的,但是他們還是有微妙的區(qū)別的。如果一定進行比較,那么應該把“$/”變量設置成為“\n\n+”才能和paragraph模式相同。(注意,這里只是比方說。實際上是不能將“$/”變量設置為規(guī)則表達式的)“$/”變量的最后一個特殊值就是可以將其設置為一個整數標量變量的引用或者是一個整數常量的引用。
在這種情況下,從文件句柄中每次讀出的數據最多是“$/”變量指定的大小。(在這里我說“最多”是因為在文件的最后有可能剩余的數據大小小于“$/”變量指定的大?。?。因此,如果你想每次讀出2kb的數據那么你可以這樣做:
代碼


    {
    local $/ = \2048;

    while (<FILE>) {
     # $_ contains the next 2048 bytes from FILE
    }
    }




“$/” 和 “$.”


注意到當改變“$/” 變量的值時候也相應的改變了perl對于記錄的定義因此也改變了“$.”變量的行為。“$.”變量實際上保存的不再是當前“行”號了,而是當前的記錄號。因此在前述的那個引文的例子中,“$.”變量將按照你所要讀出數據的文件中的每一段引文遞增。

關于“$\”

在前面的開始我提到了“$/” 和“$\”變量作為輸入和輸出的記錄分隔符。但是我們一直沒有介紹“$\”變量。

說實話,“$\”并不像“$/”那么有用。它包含了每次調用print輸出時在最后要增加的字符串。
它的默認值是空字符串,因此當你用print進行輸出時,并沒有任何東西跟在輸出的數據后面。當然如果你非常希望能有個類似pascal的輸出函數println,那么我們可以這樣寫:

代碼


    sub println {
    local $\ = "\n";
    print @_;
    }


這樣,在你每次用print輸出數據時都會在數據后面增加一個"\n"(即換行符)。

其它 Print 變量

接下來的兩個需要討論的變量是非常容易混淆,盡管它們做的是完全不同的兩件事。為了舉例說明,看下面代碼:
代碼


    my @arr = (1, 2, 3);

    print @arr;
    print "@arr";



現在,如果不仔細地看你是否知道上面兩個print調用的區(qū)別嗎?
答案是,第一個print調用會緊挨著輸出數組的三個元素,其間沒有任何分割符(輸出為:123)。然而第二個print語句輸出的元素確實以空格為分隔的(輸出為:1 2 3)。為什么會有此區(qū)別呢?

理解這個問題的關鍵就是,在每種情況下實際傳給print調用的是什么。在第一種情況下,傳遞給print的是一個數組。perl將展開傳遞過來的數組為一個列表,列表中的三個元素被視為單獨的參數。而第二種情況下,在傳遞給print之前,數組被雙引號所包含。
確切地說第二種情況也可以理解成如下的過程:
代碼


    my $string = "@arr";
    print $string;


因此,在第二種情況看來,傳遞給print函數的只是一個參數。事實上的結果就是對一個數組進行了雙引號的包含,并不影響print函數是如何對待該字符串的。



因此擺在我們面前的就是兩種情況。當print接收一組參數的時候,它將緊湊地將這些參數輸出而在輸出的參數之間沒有空格。當一個數組被
雙引號包含起來傳遞給print之前,數組的每個元素將以空格為分隔符展開為一個字符串。這兩種情況是完全不相干的。不過從我們上面舉的例子我們很容易看出人們是如何混淆這兩種情況的。
當然,如果我們愿意,perl允許我們改變這種行為。“ $,”變量保存了分隔傳遞給print函數的參數所用到的字符串。正如上面介紹的,默認分割print參數的字符是空字符,當然這都是可以更改的:

代碼


    my @arr = (1, 2, 3);
    {
    local $, = ',';

    print @arr;
    }


這段代碼將輸出1,2,3


相應地,當一個數組被雙引號包含傳遞給print函數時,展開這個數組后用來分割元素的字符則保存在“$"”變量中。代碼如下:

代碼


    my @arr = (1, 2, 3);
    {
    local $" = '+';

    print "@arr";
    }


這段代碼將輸出 1+2+3



當然,在一個print語句的使用中“$"”變量并不是必須的。你可以用在任何被雙引號包含的數組的地方。而且它也不僅僅是對數組才有效。

也可以用在哈希表上。
代碼


    my %hash = (one => 1, two => 2, three => 3);

    {
    local $" = ' < ';

    print "@hash{qw(one two three)}";
    }


這將輸出: 1 < 2 < 3
本站僅提供存儲服務,所有內容均由用戶發(fā)布,如發(fā)現有害或侵權內容,請點擊舉報
打開APP,閱讀全文并永久保存 查看更多類似文章
猜你喜歡
類似文章
perl基本語法
Perl簡明教程
【轉載】從C到Perl
Perl 筆記
該學點編程知識了
我愛 Ruby 的三十七個理由-開發(fā)者網絡-Ruby-天極Yesky
更多類似文章 >>
生活服務
分享 收藏 導長圖 關注 下載文章
綁定賬號成功
后續(xù)可登錄賬號暢享VIP特權!
如果VIP功能使用有故障,
可點擊這里聯(lián)系客服!

聯(lián)系客服