| 導購 | 订阅 | 在线投稿
分享
 
 
 

功能豐富的Perl:編寫說英語的Perl程序

2008-05-19 06:25:54  編輯來源:互聯網  简体版  手機版  移動版  評論  字體: ||

設計程序的用戶界面可能很困難而且耗時。Teodor Zlatanov 討論了如何使用 Parse::RecDescent 模塊來用簡單的英語創建用戶界面文法。他還展示了向程序添加功能或從程序除去功能時,更改文法是如何的方便。另外還與標准的 CLI 解析器和 GUI 進行了比較,討論了這種方法的優缺點。

隨功能一起發展的很棒的用戶界面

因爲用戶界面是程序最初的入口,所以它必須能夠用于多種目的。必須向用戶提供對程序所有功能的合適訪問。在向程序添加更多功能時(這幾乎是必然發生的情況),它必須是可擴展的。必須具備靈活性,可以接受常用命令的縮寫和快捷方式。它不應該有層疊的菜單或瀑布式單詞,這樣會讓用戶感到迷惑。無可否認,以上所有這些要求對程序員來說都是複雜的約束,對此沒有一種很好的解決方案能把它們全包括。許多軟件産品開發人員到最後再解決用戶界面問題,把它作爲一種事後來考慮的問題。另外一些開發人員則首先主要考慮用戶界面,讓功能僅僅成爲界面設計選擇的結果。這些都不是理想的方法。用戶界面(UI)應該隨著程序功能的發展而發展,兩者就象一枚硬幣的正反面。

這裏我們將面向解析的方法用于用戶界面。雖然這種方法適合于 GUI 界面,但本文不討論 GUI 設計。我們將專門討論基于文本的 UI。首先,將簡要介紹標准的文本 UI 設計選擇,使您能熟悉該環境。然後,將展示 Parse::RecDescent 解決方案,事實證明它是靈活、直觀和易于編寫的!

注:爲了運行我們所討論的某些程序,將需要 Parse::RecDescent CPAN 模塊。

用傳統的 Unix 方式創建的簡單用戶界面

Unix 用戶非常熟悉基于文本的 UI 模型。設想有一個 Perl 程序,讓我們先看一下這個模型用于該程序的簡單實現。標准的 Getopt::Std 模塊簡化了命令行參數的解析。這個程序僅僅爲了說明 Getopt::Std 模塊(沒有實際用途)。請參閱本文後面的參考資料。

使用 Getopt::Std 的命令行開關

#!/usr/bin/perl -w

use strict;# always use strict, it's a good habit

use Getopt::Std;# see "perldoc Getopt::Std"

my %options;

getopts('f:hl', \%options);# read the options with getopts

# uncomment the following two lines to see what the options hash contains

#use Data::Dumper;

#print Dumper \%options;

$options{h} && usage();# the -h switch

# use the -f switch, if it's given, or use a default configuration filename

my $config_file = $options{f} || 'first.conf';

print "Configuration file is $config_file\n";

# check for the -l switch

if ($options{l})

{

system('/bin/ls -l');

}

else

{

system('/bin/ls');

}

# print out the help and exit

sub usage

{

print

first.pl [-l] [-h] [-f FILENAME]

Lists the files in the current directory, using either /bin/ls or

/bin/ls -l.

The -f switch selects a different configuration file.

The -h switch prints this help.

EOHIPPUS

exit;

}

簡單的事件循環

當命令行參數不夠用時,下一步是編寫一個事件循環。在這種方案中,仍然可接受命令行參數,並且有時只使用命令行參數就足夠了。然而,事件循環支持用戶在不輸入任何參數的情形下調用程序,以及看到提示符。在此提示符下,通常可使用 help 命令,這將打印出更詳細的幫助。有時,這個 help 甚至可以是一個單獨的輸入提示符,有一個完整的軟件子系統來專門負責它。

帶有命令行開關的事件循環

#!/usr/bin/perl -w

use strict; # always use strict, it's a good habit

use Getopt::Std; # see "perldoc Getopt::Std"

my %options;

getopts('f:hl', \%options); # read the options with getopts

# uncomment the following two lines to see what the options hash contains

#use Data::Dumper;

#print Dumper \%options;

$options{h} && usage(1); # the -h switch, with exit option

# use the -f switch, if it's given, or use a default configuration filename

my $config_file = $options{f} || 'first.conf';

print "Configuration file is $config_file\n";

# check for the -l switch

if ($options{l})

{

system('/bin/ls -l');

}

else

{

my $input; # a variable to hold user input

do

{

print "Type 'help' for help, or 'quit' to quit\n- ";

$input = ;

print "You entered $input\n"; # let the user know what we got

# note that 'listlong' matches /list/, so listlong has to come first

# also, the i switch is used so upper/lower case makes no difference

if ($input =~ /listlong/i)

{

system('/bin/ls -l');

}

elsif ($input =~ /list/i)

{

system('/bin/ls');

}

elsif ($input =~ /help/i)

{

usage();

}

elsif ($input =~ /quit/i)

{

exit;

}

}

while (1); # only 'quit' or ^C can exit the loop

}

exit; # implicit exit here anyway

# print out the help and exit

sub usage

{

my $exit = shift @_ || 0; # don't exit unless explicitly told so

print

first.pl [-l] [-h] [-f FILENAME]

The -l switch lists the files in the current directory, using /bin/ls -l.

The -f switch selects a different configuration file.

The -h

switch prints this help.

Without the -l or -h arguments, will show

a command prompt.

Commands you can use at the prompt:

list:

list the files in the current directory

listlong:

list the files in the current directory in long format

help:

print out this help

quit:

quit the program

EOHIPPUS

exit if $exit;

}

這裏,通常會有三種選擇:

由于可能會有多個開關組合,所以程序的 UI 會複雜到不可忍受的程度。

UI 將發展爲 GUI。

從頭重新開發 UI,使其至少帶有一些解析功能。

第一種選擇太可怕,難以去想象。這裏不討論第二種選擇,但它的確在向後兼容性和靈活性方面提出了有趣的挑戰。第三種選擇是本文下面要討論的內容。

Parse::RecDescent 的快速教程

Parse::RecDescent 是一個用于解析文本的模塊。通過幾個簡單構造就可以用它完成幾乎所有的解析任務。更高級的文法構造可能會讓人望而生畏,不過在大多數用途中不需要這麽高級的文法。

Parse::RecDescent 是一個面向對象的模塊。它圍繞著文法創建解析器對象。文法(grammar)是一組以文本形式表示的規則。下面這個示例是一條匹配單詞的規則:

word 規則

word: /\w+/

這條規則一次或多次匹配字符(\w)。跟在冒號後的部分稱爲産品(production)。一條規則必須包含至少一個産品。一個産品可以包含其它規則或直接要匹配的內容。下面這個示例是一條規則,它可以匹配一個單詞、另一條規則(non-word)或一個錯誤(如果其它兩個都失敗):

另一些産品

token: word | non-word |

word: /\w+/

non-word: /\W+/

每個産品也可以包含一個用花括號括起的操作:

産品中的操作

print: /print/i { print_function(); }

如果操作是産品中的最後一項,則操作的返回碼決定産品是否成功。該操作是一種空産品,它將總是會匹配,除非它返回 0。

可以用 (s) 修飾符指定多個標記(token):

一個産品中帶一個或多個標記

word: letter(s)

letter: /\w/

也可以將 (?)(0 或 1)和 (s?)(0 到 N)修飾符作爲可選關鍵字來使用。

可以通過 $item[position] 或 $item{name} 機制來訪問産品中的任何內容。請注意,在第二種情形中,兩個單詞的名稱是相同的,所以必須使用位置查找。在第三種情形中,單詞數組以數組引用的形式存儲在 $item{word} 中。如果在産品中使用可選項,則數組定位方案將肯定無法很好地工作。一般來說,無論如何都應避免使用這種方案,因爲通過名稱查找的方式總是更方便更簡單:

使用 %item 和 @item 變量

print: /print/i word { print_function($item{word}); }

print2: /print2/i word word { print_function($item[1], $item[2]); }

print3: /print3/i w

  設計程序的用戶界面可能很困難而且耗時。Teodor Zlatanov 討論了如何使用 Parse::RecDescent 模塊來用簡單的英語創建用戶界面文法。他還展示了向程序添加功能或從程序除去功能時,更改文法是如何的方便。另外還與標准的 CLI 解析器和 GUI 進行了比較,討論了這種方法的優缺點。   隨功能一起發展的很棒的用戶界面   因爲用戶界面是程序最初的入口,所以它必須能夠用于多種目的。必須向用戶提供對程序所有功能的合適訪問。在向程序添加更多功能時(這幾乎是必然發生的情況),它必須是可擴展的。必須具備靈活性,可以接受常用命令的縮寫和快捷方式。它不應該有層疊的菜單或瀑布式單詞,這樣會讓用戶感到迷惑。無可否認,以上所有這些要求對程序員來說都是複雜的約束,對此沒有一種很好的解決方案能把它們全包括。許多軟件産品開發人員到最後再解決用戶界面問題,把它作爲一種事後來考慮的問題。另外一些開發人員則首先主要考慮用戶界面,讓功能僅僅成爲界面設計選擇的結果。這些都不是理想的方法。用戶界面(UI)應該隨著程序功能的發展而發展,兩者就象一枚硬幣的正反面。   這裏我們將面向解析的方法用于用戶界面。雖然這種方法適合于 GUI 界面,但本文不討論 GUI 設計。我們將專門討論基于文本的 UI。首先,將簡要介紹標准的文本 UI 設計選擇,使您能熟悉該環境。然後,將展示 Parse::RecDescent 解決方案,事實證明它是靈活、直觀和易于編寫的!   注:爲了運行我們所討論的某些程序,將需要 Parse::RecDescent CPAN 模塊。   用傳統的 Unix 方式創建的簡單用戶界面   Unix 用戶非常熟悉基于文本的 UI 模型。設想有一個 Perl 程序,讓我們先看一下這個模型用于該程序的簡單實現。標准的 Getopt::Std 模塊簡化了命令行參數的解析。這個程序僅僅爲了說明 Getopt::Std 模塊(沒有實際用途)。請參閱本文後面的參考資料。   使用 Getopt::Std 的命令行開關   #!/usr/bin/perl -w   use strict; # always use strict, it's a good habit   use Getopt::Std; # see "perldoc Getopt::Std"   my %options;   getopts('f:hl', \%options); # read the options with getopts   # uncomment the following two lines to see what the options hash contains   #use Data::Dumper;   #print Dumper \%options;   $options{h} && usage(); # the -h switch   # use the -f switch, if it's given, or use a default configuration filename   my $config_file = $options{f} || 'first.conf';   print "Configuration file is $config_file\n";   # check for the -l switch   if ($options{l})   {   system('/bin/ls -l');   }   else   {   system('/bin/ls');   }   # print out the help and exit   sub usage   {   print   first.pl [-l] [-h] [-f FILENAME]   Lists the files in the current directory, using either /bin/ls or   /bin/ls -l.   The -f switch selects a different configuration file.   The -h switch prints this help.   EOHIPPUS   exit;   }   簡單的事件循環   當命令行參數不夠用時,下一步是編寫一個事件循環。在這種方案中,仍然可接受命令行參數,並且有時只使用命令行參數就足夠了。然而,事件循環支持用戶在不輸入任何參數的情形下調用程序,以及看到提示符。在此提示符下,通常可使用 help 命令,這將打印出更詳細的幫助。有時,這個 help 甚至可以是一個單獨的輸入提示符,有一個完整的軟件子系統來專門負責它。   帶有命令行開關的事件循環   #!/usr/bin/perl -w   use strict; # always use strict, it's a good habit   use Getopt::Std; # see "perldoc Getopt::Std"   my %options;   getopts('f:hl', \%options); # read the options with getopts   # uncomment the following two lines to see what the options hash contains   #use Data::Dumper;   #print Dumper \%options;   $options{h} && usage(1); # the -h switch, with exit option   # use the -f switch, if it's given, or use a default configuration filename   my $config_file = $options{f} || 'first.conf';   print "Configuration file is $config_file\n";   # check for the -l switch   if ($options{l})   {   system('/bin/ls -l');   }   else   {   my $input; # a variable to hold user input   do   {   print "Type 'help' for help, or 'quit' to quit\n- ";   $input = ;   print "You entered $input\n"; # let the user know what we got   # note that 'listlong' matches /list/, so listlong has to come first   # also, the i switch is used so upper/lower case makes no difference   if ($input =~ /listlong/i)   {   system('/bin/ls -l');   }   elsif ($input =~ /list/i)   {   system('/bin/ls');   }   elsif ($input =~ /help/i)   {   usage();   }   elsif ($input =~ /quit/i)   {   exit;   }   }   while (1); # only 'quit' or ^C can exit the loop   }   exit; # implicit exit here anyway   # print out the help and exit   sub usage   {   my $exit = shift @_ || 0; # don't exit unless explicitly told so   print   first.pl [-l] [-h] [-f FILENAME]   The -l switch lists the files in the current directory, using /bin/ls -l.   The -f switch selects a different configuration file.   The -h   switch prints this help.   Without the -l or -h arguments, will show   a command prompt.   Commands you can use at the prompt:   list:   list the files in the current directory   listlong:   list the files in the current directory in long format   help:   print out this help   quit:   quit the program   EOHIPPUS   exit if $exit;   }   這裏,通常會有三種選擇:   由于可能會有多個開關組合,所以程序的 UI 會複雜到不可忍受的程度。   UI 將發展爲 GUI。   從頭重新開發 UI,使其至少帶有一些解析功能。   第一種選擇太可怕,難以去想象。這裏不討論第二種選擇,但它的確在向後兼容性和靈活性方面提出了有趣的挑戰。第三種選擇是本文下面要討論的內容。   Parse::RecDescent 的快速教程   Parse::RecDescent 是一個用于解析文本的模塊。通過幾個簡單構造就可以用它完成幾乎所有的解析任務。更高級的文法構造可能會讓人望而生畏,不過在大多數用途中不需要這麽高級的文法。   Parse::RecDescent 是一個面向對象的模塊。它圍繞著文法創建解析器對象。文法(grammar)是一組以文本形式表示的規則。下面這個示例是一條匹配單詞的規則:   word 規則   word: /\w+/   這條規則一次或多次匹配字符(\w)。跟在冒號後的部分稱爲産品(production)。一條規則必須包含至少一個産品。一個産品可以包含其它規則或直接要匹配的內容。下面這個示例是一條規則,它可以匹配一個單詞、另一條規則(non-word)或一個錯誤(如果其它兩個都失敗):   另一些産品   token: word | non-word |   word: /\w+/   non-word: /\W+/   每個産品也可以包含一個用花括號括起的操作:   産品中的操作   print: /print/i { print_function(); }   如果操作是産品中的最後一項,則操作的返回碼決定産品是否成功。該操作是一種空産品,它將總是會匹配,除非它返回 0。   可以用 (s) 修飾符指定多個標記(token):   一個産品中帶一個或多個標記   word: letter(s)   letter: /\w/   也可以將 (?)(0 或 1)和 (s?)(0 到 N)修飾符作爲可選關鍵字來使用。   可以通過 $item[position] 或 $item{name} 機制來訪問産品中的任何內容。請注意,在第二種情形中,兩個單詞的名稱是相同的,所以必須使用位置查找。在第三種情形中,單詞數組以數組引用的形式存儲在 $item{word} 中。如果在産品中使用可選項,則數組定位方案將肯定無法很好地工作。一般來說,無論如何都應避免使用這種方案,因爲通過名稱查找的方式總是更方便更簡單:   使用 %item 和 @item 變量   print: /print/i word { print_function($item{word}); }   print2: /print2/i word word { print_function($item[1], $item[2]); }   print3: /print3/i w   
󰈣󰈤
王朝萬家燈火計劃
期待原創作者加盟
 
 
 
>>返回首頁<<
 
 
 
 
 熱帖排行
 
王朝網路微信公眾號
微信掃碼關註本站公眾號 wangchaonetcn
 
 
靜靜地坐在廢墟上,四周的荒凉一望無際,忽然覺得,淒涼也很美
© 2005- 王朝網路 版權所有