官术网_书友最值得收藏!

1.3 改進(jìn)命令行參數(shù)

輸入?yún)?shù)都在一個(gè)數(shù)組(@ARGV)中,這樣使用起來還有些不便。我們還需要便捷地知道對應(yīng)某個(gè)選項(xiàng)的參數(shù)值。

在開始編寫代碼之前,我們先約定:

1)所有的輸入?yún)?shù),由選項(xiàng)和對應(yīng)的參數(shù)值組成。不存在某個(gè)不屬于任何選項(xiàng)的參數(shù)值。

2)每個(gè)選項(xiàng)對應(yīng)至少一個(gè)參數(shù)值。不支持沒有參數(shù)值的選項(xiàng),即類似開關(guān)的選項(xiàng)。

我們以Linux中常見的復(fù)制命令為例:

cp -i file_a file_b

其中“-i”就是一個(gè)沒有任何參數(shù)值的選項(xiàng),該命令只在file_b存在的情況下,詢問用戶是否繼續(xù)復(fù)制動作覆蓋file_b。file_a或file_b都不屬于任何選項(xiàng),cp命令只是依據(jù)它們的位置來決定其意義:第一個(gè)參數(shù)作為輸入文件,第二個(gè)參數(shù)作為輸出文件。

如果使用Perl程序完成上述cp命令的功能,依照上面的約定,程序(假設(shè)為mycp)的參數(shù)可設(shè)計(jì)成如下:

-input file
-output file
-overlap [yes|no]

相應(yīng)地,我們的程序,需要這樣運(yùn)行:

mycp -input file_a -output file_b -overlap no

當(dāng)然,這些選項(xiàng)的相對位置是隨意的,也可以這樣運(yùn)行:

mycp -overlap no -output file_b -input file_a

本節(jié),我們將改進(jìn)代碼1-1的讀取命令行參數(shù)的程序,把參數(shù)都存儲到一個(gè)散列(hash)中。我們假設(shè)每個(gè)選項(xiàng)對應(yīng)一個(gè)參數(shù)值,不多也不少,并且用戶的輸入是正確的:-optA pv_a -optB pv_b …。

代碼1-2 ch01/read_argument_v2.pl

 1 #!/usr/local/bin/perl
 2 
 3 my ($opt, %value_of_opt) ;
 4 
 5 for my $arg ( @ARGV ) {
 6   if ( $arg =~ /^-/ ) {
 7     $opt = $arg;
 8   }
 9   else {
10     $value_of_opt{$opt} = $arg;
11   }
12 }
13 
14 for my $opt ( keys %value_of_opt ) {
15   print "$opt => $value_of_opt{$opt}\n";
16 }
17 
18 exit 0;

如果我們運(yùn)行:

./read_argument_v2.pl -a a1 -b b1 -c c1

那么程序會輸出:

Command is: ./read_argument_v2.pl
-a => a1
-b => b1
-c => c1

第3行,聲明了兩個(gè)變量:一個(gè)標(biāo)量$opt,一個(gè)散列%value_of_opt。

第6~11行,是一個(gè)if/else判斷結(jié)構(gòu)。

第6行條件中的$arg =~ /^-/是一個(gè)正則表達(dá)式匹配,如果$arg以短橫線(“-”)開頭,那么該匹配返回1,否則返回空(就是什么都沒有),通常稱之為空字符串。有關(guān)正則表達(dá)式的內(nèi)容,留在第3章進(jìn)行詳細(xì)介紹。

第7行,把$arg的值賦值給$opt,留給下一次循環(huán)(第10行)使用。

第10行,把$arg賦值給散列中對應(yīng)的鍵$opt。也就是說,給散列%value_of_opt中增加一個(gè)鍵/值對,其中鍵是$opt,值是$arg。

下面我們依次介紹代碼1-2中出現(xiàn)的散列、判斷結(jié)構(gòu)if/else以及“真”與“假”。

1.3.1 散列

散列就是無序的鍵/值對,假設(shè)只有標(biāo)量和數(shù)組,沒有散列,理論上,也可以表示各類數(shù)據(jù)?,F(xiàn)有一組如下數(shù)據(jù):

ZheJiang HangZhou
JiangXi NanChang
XiZang LaSa
…

可以如下存儲數(shù)據(jù):

my @provinces = ("ZhaJiang", "JiangXi", "XiZang");
my @pccs = ("HangZhou", "NanChang", "LaSa");

假設(shè)我們想知道江西的省會,可以通過一個(gè)循環(huán),找到JiangXi在數(shù)組@provinces中的序號(即1,數(shù)組的序號從0開始),然后把這個(gè)1存儲在某個(gè)變量中(比如$n),然后取出$pccs[$n],這就是我們想要的信息。

由于這樣的情形很常見,需要更高效簡便的處理方式,因此很多高級語言都提供了散列或者功能類似的數(shù)據(jù)類型。Perl的散列名必須以%開頭,后面緊跟一個(gè)字母或者下劃線,后面還可以繼續(xù)跟多個(gè)字母、數(shù)字或下劃線。散列的初始化如下所示:

%pcc_of = (
  'ZheJiang'    => 'HangZhou',
  'JiangXi'     => 'NanChang',
  'XiZang'      => 'LaSa',
);

與數(shù)組類似,散列由圓括號包圍,鍵/值對用逗號分隔。每個(gè)單元都指定了一個(gè)鍵,在=>的左邊;同時(shí)指定了與這個(gè)鍵配對的值,在=>的右邊。鍵和值都是標(biāo)量。如果要取用某個(gè)鍵指向的值,可以這樣:

print $pcc_of{'JiangXi'}, "\n"; 

輸出:

NanChang

散列中的鍵是唯一的,即同一個(gè)散列中不存在兩個(gè)同名的鍵。

散列的常用函數(shù)有keys、values等。keys返回散列的全部的鍵,組成一個(gè)數(shù)組。values返回散列的所有的值,組成一個(gè)數(shù)組。需要留意的是,keys返回的數(shù)組中,各鍵的次序與該散列初始化化時(shí)各鍵的次序無關(guān)。

散列是靈活的,可以增減鍵值對??墒褂胐elete函數(shù)進(jìn)行刪除操作,也可直接賦值進(jìn)行新增操作。

delete $one_hash{'akey'};
$one_hash{'akey'} = "something";

1.3.2 判斷結(jié)構(gòu)if

常用的判斷結(jié)構(gòu)有if/elsif/else。其中elsif/else分支是可選的,elsif分支可以有多個(gè),else分支最多只能有一個(gè)。

  if ( condition1 ) {
    sentences1 …
  }
  elsif ( condition2 ) {
    sentences2 …
  }
  elsif ( condition3 ) {
    sentences3 …
  }
  else {
    sentencesN …
  }
 
outer_sentence …

上述判斷結(jié)構(gòu)會從if的條件開始判斷,如果condition1為“真”,則執(zhí)行后面大括號中的語句sentences1;如果為“假”,則繼續(xù)檢查下一個(gè)條件,直到某個(gè)分支的條件為“真”,就執(zhí)行那個(gè)分支的語句,執(zhí)行該語句后,離開整個(gè)if/elsif/else結(jié)構(gòu)。如果沒有任何條件為“真”,且存在else分支,則執(zhí)行else分支的語句。

無論執(zhí)行哪個(gè)分支的語句,都會離開整個(gè)判斷結(jié)構(gòu),來到結(jié)構(gòu)外部,繼續(xù)后面的語句outer_sentence。

1.3.3 “真”與“假”

什么是“真”,什么是“假”?這既可以是一個(gè)深奧的哲學(xué)問題,也可以是一個(gè)簡單的Perl語法問題。在這里,我們僅討論后者。

Perl沒有提供專門的變量或常量來表示“真”與“假”。任何標(biāo)量(或常量)都可以成為判斷結(jié)構(gòu)的條件。那么Perl怎么判斷這個(gè)標(biāo)量是“真”還是“假”呢?它有以下規(guī)則:

  • 未被賦值的,是假;
  • 數(shù)字0,字符串'0'(零),空字符串'',是假;
  • 其余皆為真。
my $t1 = 0;   # false
my $t2 = '0'; # false
my $t3 = '' ; # false
my $t4 = ' '; # true

除了單個(gè)的“真”“假”表達(dá)式,Perl還支持邏輯表達(dá)式的組合。有兩組“或與非”邏輯操作符會經(jīng)常使用。

第1組是“!”“&&”“||”(見表1-1)。

表1-1 邏輯操作符1

000

第2組是“not”“and”“or”(見表1-2)。

表1-2 邏輯操作符2

000

不用背誦記憶它們之間的優(yōu)先級,只要使用圓括號即可,例如:

(expr1 or expr2) and (expr3 or expr4) and (! expr5) …

這樣可使代碼的邏輯結(jié)構(gòu)更清晰,也避免了我們對優(yōu)先級的預(yù)期出現(xiàn)誤判。

既然有兩組邏輯操作符,那么如何選擇呢?有沒有特殊的規(guī)則需要記憶?請放心,沒有!我常用的是“and”“or”“!”,因?yàn)槲以谳斎?amp;&和||這類“疊詞”時(shí)常常會少輸入一個(gè)字符,造成語法錯誤。使用!而不是not的原因是,后者字符多了兩倍,而且前者具有很好的警示作用(即取“反”)。

不需要記憶的優(yōu)先級:

1)!、&&、||這一組的各個(gè)邏輯操作符的優(yōu)先級分別高于相對應(yīng)的not、and、or。

2)同一組內(nèi),not(!)的優(yōu)先級高于and(&&)的優(yōu)先級,and(&&)的優(yōu)先級高于or(||)的優(yōu)先級。

3)將優(yōu)先級按從高到低排序并匯總起來就是:! 高于 not 高于 && 高于 and 高于 || 高于 or。

主站蜘蛛池模板: 繁昌县| 青阳县| 镇安县| 邛崃市| 廉江市| 大姚县| 大埔区| 香港| 田东县| 诏安县| 开平市| 平原县| 深圳市| 古蔺县| 光山县| 虎林市| 大名县| 浪卡子县| 定兴县| 西和县| 富蕴县| 纳雍县| 秭归县| 广灵县| 大厂| 丹寨县| 宁波市| 林周县| 明溪县| 黔东| 新野县| 融水| 合川市| 丰城市| 康定县| 额尔古纳市| 渝中区| 额济纳旗| 龙游县| 绩溪县| 长兴县|