2012年9月26日 星期三

Perl 教學 -- 函數與字串處理

Perl 教學 -- 函數與字串處理

This tutorial is copyrighted and provided as is. You are welcomed to use it for non-commercial purpose.
Written by: 國立中興大學資管系呂瑞麟 Eric Jui-Lin Lu

請勿轉貼
看其他教材

函數 (Function):

  1. 建立與使用函數: 執行
    • 這個範例用來說明如何宣告一個函數,並呼叫它。程式碼如下:
      #!/usr/bin/perl
      
      sub Footer
      {
         print "<h2>Perl Program Using Functions</h2>\n";
         print "\n</body>\n";
         print "</html>\n";
      }
      
      print "Content-type: text/html\n\n";
      print "<html>\n";
      print "<head>\n";
      print "<title>Perl Program Using Functions</title>\n";
      print "</head>\n\n";
      &Footer;
        
    • 在程式碼中,我們宣告了一個名為 Footer 的函數(綠色的部分);函數宣告 的基本語法是使用保留字 sub 並在其後加上函數名稱(這個範例中使用的 是 Footer),函數名稱之後加上一對大括號,在大括號中加入必要的程式碼。
    • 呼叫函數的語法是 &函數名稱,因此呼叫 Footer 的方式如程式碼 中紅色的部分。

  2. 函數間傳送資料 (I): 執行
    • 在前一個範例中,我們宣告了一個 Footer 的函數,但是該函數 並無法接收呼叫端傳送過來的參數,但是在大多數的程式中,能夠宣告一個能接受 參數的函數是必要的,這個範例就是用於說明該方式。
    • 程式碼如下:
      #!/usr/bin/perl
      
      sub Header
      {
        print "Content-type: text/html\n\n";
        print "<html>\n";
        print "<head>\n";
        print "<title>@_</title>\n";
        print "</head>\n\n";
      }
      
      sub Footer
      {
        print "<h2>Perl Program Using Functions</h2>\n";
        print "\n</body>\n";
        print "</html>\n";
      }
      
      &Header("Perl Program Using Functions");
      &Footer;
        
    • 在程式中,我們把前一個範例中的 print 敘述全部定義在一個名為 Header 的函數(如綠色部分),然後呼叫它(如紅色部分)。請注意,呼叫端在函數名稱 之後加上了一對括號,並在括號內加入了一個字串,這代表呼叫 Header 並將 字串 "Perl Programming Using Functions" 傳給 Header;如果 Header 需要取用 該參數內容,則使用 @_
    • 嚴謹的說,@_ 代表一個呼叫端傳送過來的陣列。在本範例中,由於 只傳遞了一個參數,因此該陣列只有一個元素,我們也可以單獨使用 $_[0] 來取得該參數的內容,請試試看!

  3. 函數間傳送資料 (II): 執行
    • 這個範例用於說明如何傳遞多個參數資料給函數,而且函數產生的結果 可以回傳給呼叫端。
    • 程式碼如下:
      #!/usr/bin/perl
      
      sub Root
      {
        my($a, $b, $c) = @_;
        my($tmp, $x1, $x2);
        $tmp = sqrt($b ** 2 - 4.0 * $a * $c);
        $x1 = (-$b + $tmp) / (2.0 * $a);
        $x2 = (-$b - $tmp) / (2.0 * $a);
        return ($x1,  $x2);
      }
      
      
      $a = 1.0;
      $b = -2.0;
      $c = 1.0;
      @x = &Root($a, $b, $c);
      print "Content-type: text/html\n\n";
      print "x1 = $x[0]; and x2 = $x[1]\n";
        

    • 呼叫 Root 函數的時候,程式也傳遞三個參數資料(分別是變數 a、b、c; 這三個是全域變數),函數接收到資料後,將陣列資料 @_ 分別指定給 $a, $b, $c,其中,由於 ($a, $b, $c) 前面有 my, 因此這些變數 a、b、c 代表區域變數,而且只能在 Root 函數內使用;另外,Root 函數 又宣告了區域變數 tmp, x1, 和 x2。
    • 等到 Root 函數計算出結果後,它以 return 將變數值 x1 和 x2 (嚴謹的說,將包含變數 x1 和 x2 的陣列)回傳給呼叫端。
    • 呼叫端(紅色部分)將 Root 函數回傳的結果指定給一個名為 x 的陣列, 而其內容就可以 $x[0]$x[1] 的方式將資料取出。
  4. 使用 require: 執行
    • require 類似 C 語言的 include;基本上,它用來將另一個檔案的 內容"包"進檔案。
    • 原始碼:
      #!/usr/bin/perl
      
      require "req.pl";
      
      &Header("Perl Program Using Functions");
      &Footer;
        
      在程式碼中,我們利用 require 將一個名為 req.pl 的檔案包進來; 如以下的說明,req.pl 包含之前定義的 Footer 和 Header 兩個函數。這樣的 作法有一個好處,那就是 req.pl 的內容可以在多個程式中被重複使用。
    • req.pl 的程式碼如下:
      #!/usr/bin/perl
      
      sub Header
      {
        print "Content-type: text/html\n\n";
        print "<html>\n";
        print "<head>\n";
        print "<title>@_</title>\n";
        print "</head>\n\n";
      }
      
      sub Footer
      {
        print "<h2>Perl Program Using Functions</h2>\n";
        print "\n</body>\n";
        print "</html>\n";
      }
      
      return 1;  # this is required.
        
      請注意,在程式碼的最後一行必須加上如紅色部分的 return 1;;也 就是說,所有被包進某個檔案的程式(如本例中的 req.pl),其最後一行必須 加上 return 1;



日期函數

在撰寫 CGI-Perl 程式的時候,經常我們需要抓取系統的時間或日期。 Perl 提供了幾個有用的時間函數,你可以命令提示字元的視窗內下 perldoc perlfunc 的指令,然後搜尋 localtimegmtime。 本範例我們介紹 localtime 的使用方式:
#!/usr/bin/perl
($sec, $min,$hour,$mday,$mon,$year,$wday,$yday,$isdst)  = localtime(time);
print "秒: $sec\n";
print "分: $min\n";
print "時: $hour\n";
print "一個月的第幾天: $mday\n";
print "月: $mon 範圍是 0-11,而一月為 0\n";
print "距離 1900 年的第幾年: $year\n";
print "一周內的第幾天: $wday  範圍是 0-6,而星期日為 0\n";
print "一年內的第幾天: $yday\n";

# 如果我只想要當天的日期,
($_,$_,$_, $mday, $mon, $year, $_,$_,$_) = localtime(time);
$year = $year + 1900;
$mon = $mon + 1;
print "今天是西元 $year 年 $mon 月 $mday 日\n";
練習題: 試著將上列的程式改成顯示目前的時間? 或者 顯示民國年?

字串、搜尋、與取代

  1. 例題 I:
    #!/usr/local/bin/perl
    $url = 'www.nchu.edu.tw';
    
    # Usage: /pattern/[g][o][i]
    # g for global, o for only once, and i for case-insentitive
    # url 是否包含 nchu 字串
    if ( $url =~ /nchu/ )
    {
       print "$url is 國立中興大學.\n";
    }
    
    # 將 'edu' 取代為 EDU
    # Can you use tr? (ie. tr/edu/EDU/)
    $url =~ s/edu/EDU/;
    print "\$url is now $url.\n";
    
  2. 例題 II:
    1. 大寫變小寫
        #!/usr/local/bin/perl
        $names = "fred and mary";
        $names =~ tr/a-z/A-Z/;
        print "$names\n";
        
    2. 計算字串長度
        #!/usr/local/bin/perl
        $count = "fred and mary";
        #
        # 若不使用 =~, tr 傳回轉換的字元總數
        $count = tr/a-z //;
        print "$count\n";
        
  3. 例題 III: 在使用 GET 方法的 Form 例題中, 請在輸入欄內輸入多於 一個字並觀察其執行情形。 你應該可以看到網址輸入欄內的內容 (如果輸入的是 aaa bbb)為 input=aaa+bbb。 這是因為空格被 "+" 符號 (URL-encoded characters) 取代。常見的 URL-encoded characters 包含:
    CharacterURL-encoded characters
    Tab%09
    空格+
    !%21
    +%2B

    那麼當成是接收到 input=aaa+bbb 的時候,它要如何將 + 轉換成空格呢?以下我們利用 GET 和 POST 的範例,分別列出轉換的方式。

    • GET 的方式:
      • form 表單:
        請輸入文字(GET):
      • 該表單呼叫 sub.pl,而其程式碼如下:
        #!/usr/local/bin/perl
        print "Content-type: text/plain\n\n";
        $input = $ENV{'QUERY_STRING'};
        
        # translate + into space.
        $input =~ tr/+/ /;
        print "$input.\n";
        
        # s: substitute
        # \d: a number, A-F: A,B,C,D,E,F, a-f: a,b,c,d,e,f
        # [\dA-Fa-f]: either a number, A, B, ... , F, a, b, ..., or f.
        # pack("c", hex($1)): transform %[][] into a character ("c").
        # e: treat pack() as an expression instead of a string.
        # $input =~ s/%(..)/pack("c", hex($1))/eg;
        $input =~ s/%([\dA-Fa-f][\dA-Fa-f])/pack("c", hex($1))/eg;
        print "$input.\n";
        
      • 程式碼中,除了第一段是進行之前說過的"將 + 轉換成空格",第二段我們 使用了更進階的方式將所有 URL-encoded characters 轉換成字串。為了容易說明, 請在表單中輸入一個中文字(例如),執行後,讀者應該可以從網頁或者 瀏覽器的 URL 欄位看到,(不含雙引號)這個字被轉換成的 URL-encoded characters 是 %AA%C5,這樣的內容程式必須加以處理才能轉換 成我們需要的。轉換的規則如下:我們需要從資料內找出所有的 URL-encoded characters,而這些字元都符合 %XX 格式,而 X 代表 16 進位的數字(也就是 0-9A-F);Perl 的搜尋規則即為 %([\dA-Fa-f][\dA-Fa-f]);找到字元之後,我們利用 pack() 方法,將其 16 進位的資料轉換成字串。 pack() 的第一個參數 "c" 就是指定轉換成字串的設定,我們也可以 轉換成其他資料型態,有興趣的讀者,可以參考 pack 的用法。


    • POST 的方式:
      • form 表單:
        請輸入文字(POST):
      • 該表單呼叫 subp.pl:因為該程式除了經由 POST 方式來讀取資料而跟 sub.pl 不同以外,其他部分相同,因此不再贅述。





Written by: 國立中興大學資管系呂瑞麟 Eric Jui-Lin Lu



沒有留言:

張貼留言