#
用傳統的 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 <<EOHIPPUS; 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; }
大家經常使用正則表達式的字符集從字符串中抽取或排除中文字符,但是這樣做 很費事,效果也并不是很理想。實際上Perl從5.6開始已經開始在內部使用utf8編碼 來表示字符,也就是說對中文以及其他語言字符的處理應該是完全沒有問題的。關鍵 在于目前使用的編輯器以及文件格式并不都能很好地支持utf8,委屈了Perl的強大能力。 實際上我們只需要利用好Encode這個模塊便能充分發揮Perl的utf8字符的優勢了。
????下面就以中文文本的處理為例進行說明(注意:編輯下面這段程序不能用使用utf8 編碼的編輯器),比如有一個字符串"測試文本",我們想要把這個中文字符串拆成單個 字符,可以這樣寫: use?Encode; use?Encode::CN;?#可寫可不寫 $dat="測試文本"; $str=decode("gb2312",$dat); @chars=split?//,$str; foreach?$char?(@chars)?{ ????????print?encode("gb2312",$char),"\n"; } 結果大家試一試就知道了,應該是令人滿意的。
????這里主要用到了Encode模塊的decode、encode函數。要了解這兩個函數的作用我們 需要清楚幾個概念: 1、Perl字符串是使用utf8編碼的,它由Unicode字符組成而不是單個字節,每個utf8編 碼的Unicode字符占1~4個字節(變長)。 2、進入或離開Perl處理環境(比如輸出到屏幕、讀入和保存文件等等)時不是直接使用 Perl字符串,而需要把Perl字符串轉換成字節流,轉換過程中使用何種編碼方式完全取決 于你(或者由Perl代勞)。一旦Perl字符串向字節流的編碼完成,字符的概念就不存在了 ,變成了純粹的字節組合,如何解釋這些組合則是你自己的工作。
????我們可以看出如果想要Perl按照我們的字符概念來對待文本,文本數據就需要一直用 Perl字符串的形式存放。但是我們平時寫出的每個字符一般都被作為純ASCII字符保存( 包括在程序中明文寫出的字符串),也就是字節流的形式,這里就需要encode和decode函 數的幫助了。
????encode函數顧名思義是用來編碼Perl字符串的。它將Perl字符串中的字符用指定的編 碼格式編碼,最終轉化為字節流的形式,因此和Perl處理環境之外的事物打交道經常需要 它。其格式很簡單: ????????$octets?=?encode(ENCODING,?$string?[,?CHECK]) 這里$string是Perl字符串,ENCODING是給定的編碼方式,$octets則是編碼之后的字節流 ,CHECK表示轉換時如何處理畸變字符(也就是Perl認不出來的字符)。一般不需要使用 CHECK,讓Perl按默認規則處理即可。 ????編碼方式視語言環境的不同有很大變化,默認可以識別utf8、ascii、ascii-ctrl、 iso-8859-1等,中文環境(CN)增加了euc-cn(gb2312與之等價)、cp936(gbk與之等價 )、hz等,還有日文環境(JP)、韓文(KR)等等,在此不一一盡數。
????decode函數則是用來解碼字節流的。它按照你給出的編碼格式解釋給定的字節流,將 其轉化為使用utf8編碼的Perl字符串,一般來說從終端或者文件取得的文本數據都應該用 decode轉換為Perl字符串的形式。它的格式為: ????????$string?=?decode(ENCODING,?$octets?[,?CHECK]) $string、ENCODING、$octets和CHECK的含義同上。
????現在就很容易理解上面寫的那段程序了。因為字符串是用明文寫出的,存放的時候已 經是字節流形式,喪失了本來的意義,所以首先就要用decode函數將其轉換為Perl字符串 ,由于漢字一般都用gb2312格式編碼,這里decode也要使用gb2312編碼格式。轉換完成后 Perl對待字符的行為就和我們一樣了,平時對字符串進行操作的函數基本上都能正確對字 符進行處理,除了那些本來就把字符串當成一堆字節的函數(如vec、pack、unpack等)。 于是split就能把字符串切成單個字符了。最后由于在輸出的時候不能直接使用utf8編碼 的字符串,還需要將切割后的字符用encode函數編碼為gb2312格式的字節流,再用print 輸出。
????Encode模塊的初步應用大概就是這樣,詳細情況還是要參閱模塊的文檔。實際上如果 我們使用UltraEditor等等支持編輯utf8編碼文件的編輯器寫程序,基本上用不著Encode 模塊,在程序開頭加上一句use?utf8就行。這時Perl默認包括程序本身在內的所有的字符 都是Unicode字符,可以隨便使用Unicode范圍內的字符,甚至可以用非英文字符作為標識 符,只是輸出的時候可能還需要用Encode模塊。比如用UE的utf8編碼模式編輯這個程序: ????????use?utf8; ????????$單價=10; ????????$數量=100; ????????$總額=$單價*$數量; ????????print?"$總額\n"; 可以在Perl?5.6以后的版本中正常運行并給出結果,是不是很爽?:)?這種模式最大的優點 就是在字符串中可以混合多種語言的文字,就算中日韓英加上阿拉伯字符都在一個字符串 中出現也沒問題;不像使用Encode模塊那樣必須固定一種編碼方式,中日韓英字符同時出 現還好辦,因為gbk包含了所有這些字符,可是再加上一些非亞洲語言字符就不一定能處 理了。所以以后用Unicode編碼應該是大勢所趨。
希望寫的這些能對大家有所幫助。
這是我的windows下的emacs: ???
 
在P e r l中,d i e函數可以用來在出現錯誤的時候停止解釋程序的運行,并輸出一條有意義的 出錯消息。正如你在前面已經看到的那樣,只要調用d i e函數,就能夠輸出類似下面的消息: ???died at scriptname line xxx
d i e函數也可以帶有一系列的參數,這些參數將取代默認消息而被輸出。如果消息的后面 沒有換行符,那么消息的結尾就附有at scriptname line xxx字樣: ???die "Cannot open";???#prints "Cannot open at scriptname scriptname line xxx"
P e r l中有一個特殊的變量$ !,它總是設置為系統需要的最后一個操作(比如磁盤輸入或輸 出)的出錯消息。當$ !用于數字上下文時,它返回一個錯誤號,這個號可能對任何人都沒有 什么用處。在字符串上下文中, $ !返回來自你的操作系統的相應的出錯消息: ???open(MYFILE, "myfile") || die "Cannot open myfile: $!\n";
不要使用$ !的值來檢查系統函數的運行是失敗還是成功。只有當系統執 行一項操作(比如文件輸入或輸出)之后, $ !才有意義,并且只有在該操作 運行失敗后, $ !才被設置。在其他時間中, $ !的值幾乎可以是任何東西,并 且是毫無意義的。
不過有時并不想使程序停止運行,只是想要發出一個警告。若要創建這樣的警告, P e r l有 一個w a r n函數可供使用。w a r n的運行方式與d i e完全一樣,你可以從下面這個代碼中看出來,不過差別是它的程序將保持運行狀態: ???if(! open(MYFILE, "output)) { ??????warn "cannot read output: $!"; ???} else { ??????;???# Reading output... ???}
1.split函數 ???%seen = ( ); ???$string = "an apple a day"; ???foreach $char (split //, $string) { ???????$seen{$char}++; ???} 2./(.)/g 但是(.)永遠不會是newline ???%seen = ( ); ???$string = "an apple a day"; ???while ($string =~ /(.)/g) { ???????$seen{$1}++; ???} 3.unpack("C*")也可以逐個處理字符:(這個例子是累加字符串里每個字符ascii碼的累加值) ???$sum = 0; ???foreach $byteval (unpack("C*", $string)) { ???????$sum += $byteval; ???} ???print "sum is $sum\n"; ???# prints "1248" if $string was "an apple a day" $sum = unpack("%32C*", $string); #這個方法比上面更快,這個返回32位的checksum值. 4 .<>是默認的輸入流,其實就是ARGV. ?????這個模擬sysv的checksum程序: ???#!/usr/bin/perl
???# sum - compute 16-bit checksum of all input files
???$checksum = 0;
???while (<>) { $checksum += unpack("%16C*", $_) }
???$checksum %= (2 ** 16) - 1;
???print "$checksum\n"; ???
???Here's an example of its use: ???% perl sum /etc/termcap
???1510 ???If you have the GNU version of sum, you'll need to call it with the —sysv option to get the same answer on the same file.
???% sum --sysv /etc/termcap
???1510 851 /etc/termcap 一個詳細的例子:
#!/usr/bin/perl
# slowcat - emulate a s l o w line printer
# usage: slowcat [-DELAY] [files ...]
$DELAY = ($ARGV[0] =~ /^-([.\d]+)/) ? (shift, $1) : 1; #這里[.]取消了.的特殊性。使其為一般意義。shift移除了@ARGV第一個變量和長度減一。
$| = 1; #不為0就強行清空輸出或打印。
while (<>) { #<>為@ARGV指定的文件句柄
for (split(//)) {
print;
select(undef,undef,undef, 0.005 * $DELAY); #select函數設置屏幕輸出。這里是設置延遲。
}
}
下載 http://members.optusnet.com.au/puyo/ruby-mode.el 放入emacs/site-lisp目錄
在.emacs中添加: ??? (autoload 'ruby-mode "ruby-mode" "Major mode for editing ruby scripts." t) ??? (setq auto-mode-alist (cons '("\\.rb$" . ruby-mode) auto-mode-alist)) ??? (setq interpreter-mode-alist (append '(("ruby" . ruby-mode)) interpreter-mode-alist)) ??? (setq load-path (append load-path '("X")))
perlcn - 簡體中文 Perl 指南
歡迎來到 Perl 的天地!
從 5.8.0 版開始, Perl 具備了完善的 Unicode (統一碼) 支援,
也連帶支援了許多拉丁語系以外的編碼方式; CJK (中日韓) 便是其中的一部份.
Unicode 是國際性的標準, 試圖涵蓋世界上所有的字符: 西方世界, 東方世界,
以及兩者間的一切 (希臘文, 敘利亞文, 亞拉伯文, 希伯來文, 印度文,
印地安文, 等等). 它也容納了多種作業系統與平臺 (如 PC 及麥金塔).
Perl 本身以 Unicode 進行操作. 這表示 Perl 內部的字符串數據可用 Unicode
表示; Perl 的函式與算符 (例如正規表示式比對) 也能對 Unicode 進行操作.
在輸入及輸出時, 為了處理以 Unicode 之前的編碼方式存放的數據, Perl
提供了 Encode 這個模塊, 可以讓你輕易地讀取及寫入舊有的編碼數據.
Encode 延伸模塊支援下列簡體中文的編碼方式 ('gb2312' 表示 'euc-cn'):
euc-cn Unix 延伸字符集, 也就是俗稱的國標碼 gb2312-raw 未經處理的 (低比特) GB2312 字符表 gb12345 未經處理的中國用繁體中文編碼 iso-ir-165 GB2312 + GB6345 + GB8565 + 新增字符 cp936 字碼頁 936, 也可以用 'GBK' (擴充國標碼) 指明 hz 7 比特逸出式 GB2312 編碼
舉例來說, 將 EUC-CN 編碼的檔案轉成 Unicode, 祗需鍵入下列指令:
perl -Mencoding=euc-cn,STDOUT,utf8 -pe1 < file.euc-cn > file.utf8
Perl 也內附了 ``piconv'', 一支完全以 Perl 寫成的字符轉換工具程序, 用法如下:
piconv -f euc-cn -t utf8 < file.euc-cn > file.utf8 piconv -f utf8 -t euc-cn < file.utf8 > file.euc-cn
另外, 利用 encoding 模塊, 你可以輕易寫出以字符為單位的程序碼, 如下所示:
#!/usr/bin/env perl # 啟動 euc-cn 字串解析; 標準輸出入及標準錯誤都設為 euc-cn 編碼 use encoding 'euc-cn', STDIN => 'euc-cn', STDOUT => 'euc-cn'; print length("駱駝"); # 2 (雙引號表示字符) print length('駱駝'); # 4 (單引號表示字節) print index("諄諄教誨", "蛔喚"); # -1 (不包含此子字符串) print index('諄諄教誨', '蛔喚'); # 1 (從第二個字節開始)
在最后一列例子里, ``諄'' 的第二個字節與 ``諄'' 的第一個字節結合成 EUC-CN
碼的 ``蛔''; ``諄'' 的第二個字節則與 ``教'' 的第一個字節結合成 ``喚''.
這解決了以前 EUC-CN 碼比對處理上常見的問題.
如果需要更多的中文編碼, 可以從 CPAN (http://www.cpan.org/) 下載
Encode::HanExtra 模塊. 它目前提供下列編碼方式:
gb18030 擴充過的國標碼, 包含繁體中文
另外, Encode::HanConvert 模塊則提供了簡繁轉換用的兩種編碼:
big5-simp Big5 繁體中文與 Unicode 簡體中文互轉 gbk-trad GBK 簡體中文與 Unicode 繁體中文互轉
若想在 GBK 與 Big5 之間互轉, 請參考該模塊內附的 b2g.pl 與 g2b.pl 兩支程序,
或在程序內使用下列寫法:
use Encode::HanConvert; $euc_cn = big5_to_gb($big5); # 從 Big5 轉為 GBK $big5 = gb_to_big5($euc_cn); # 從 GBK 轉為 Big5
請參考 Perl 內附的大量說明文件 (不幸全是用英文寫的), 來學習更多關于
Perl 的知識, 以及 Unicode 的使用方式. 不過, 外部的資源相當豐富:
-
http://www.perl.com/
-
Perl 的首頁 (由歐萊禮公司維護)
-
http://www.cpan.org/
-
Perl 綜合典藏網 (Comprehensive Perl Archive Network)
-
http://lists.perl.org/
-
Perl 郵遞論壇一覽
-
http://www.oreilly.com.cn/html/perl.html
-
簡體中文版的歐萊禮 Perl 書藉
-
http://www.pm.org/groups/asia.shtml#China
-
中國 Perl 推廣組一覽
-
http://www.unicode.org/
-
Unicode 學術學會 (Unicode 標準的制定者)
-
http://www.cl.cam.ac.uk/%7Emgk25/unicode.html
-
Unix/Linux 上的 UTF-8 及 Unicode 答客問
the Encode manpage, the Encode::CN manpage, the encoding manpage, the perluniintro manpage, the perlunicode manpage
Jarkko Hietaniemi <jhi@iki.fi>
Autrijus Tang (唐宗漢) <autrijus@autrijus.org>
1.ord函數 ??? $num = ord($char); #把字符轉換為整數 2.chr函數 ??? $char = chr($num); #把整數轉換為字符 3.printf函數 ??? printf("Number %d is character %c\n", 101, 101); #格式化輸出一個整數和字符. ??? printf "%vd\n", "fac\x{0327}ade";
??? ??? 102.97.99.807.97.100.101 ??? printf "%vx\n", "fac\x{0327}ade";
??? ??? 66.61.63.327.61.64.65 ??? ??
4.unpack函數(C*把一個字符串轉換為byte數組)(U*是指定的unicode) ??? @ascii_character_numbers = unpack("C*", "sample");
??? print "@ascii_character_numbers\n";
??? ??? 115 97 109 112 108 101
5.pack函數(C*把一個byte數組轉換為一個字符串) ??? $word = pack("C*", @ascii_character_numbers);
??? $word = pack("C*", 115, 97, 109, 112, 108, 101); # same
print "$word\n";
??? ??? sample
1.使用||來建立默認值 ??? $foo = $bar || "DEFAULT VALUE"; #如果$bar沒有值的話就使用"DEFAULT VALUE"作為$foo的值. $dir = shift(@ARGV) || "/tmp"; #如果沒有參數,,就返回"/tmp". $dir = defined($ARGV[0]) ? shift(@ARGV) : "/tmp";
2.shift函數: 移出第一個數組元素,并返回.
3.defined函數: ??? 判斷一個變量、數組或數組的一個元素是否已經被賦值。expr為變量名、數組名或一個數組元素。如果已定義,返回真,否則返回假。 4. if和unless ??? 注:if和unless意思相反! ?$a = $b if $a; ??? #如果$a為真$a賦值為$b ?$a = $b unless $a? #如果$a為假$a賦值為$b
1. 一旦我們讀出了一個記錄,通常打算去掉記錄分隔符,(缺省值為換行符字符):
??? chomp($n = <STDIN>); 注: Perl 4.0版本僅有chop()操作,去掉串的最后一個字符, 不管該字符是什么。chomp() 沒有這么大的破壞性,如果有行分隔符存在,它僅去掉行分隔符。如果你打算去掉行分隔符,就用chomp() 來代替chop()。
2.q//和 qq//前面一個是加單引號,后面一個是加雙引號.匹配形式是 /regex/ 而直接運行命令是( $x=`cmd`). $string = q[Jon 'Maddog' Orwant]; # literal single quotes $string = q{Jon 'Maddog' Orwant}; # literal single quotes $string = q(Jon 'Maddog' Orwant); # literal single quotes $string = q<Jon 'Maddog' Orwant>; # literal single quotes
3.特殊字符包括 "\n" (新行), "\033" (八進制數的字符33), "\cJ" (Ctrl-J), "\x1B" (十六進制的字符 0x1B).
4.直接輸入多行: $a = <<"EOF"; #指明了EOF為結束符 This is a multiline here document terminated by EOF on a line by itself EOF 5.prinf函數 $char = chr(0x394); $code = ord($char); printf "char %s is code %d, %#04x\n", $char, $code, $code; # %#04x表示占四位十六進制數少的話用0補齊
charDis code 916, 0x394
6.substr函數 substr函數形式如下: ??? $value = substr($string, $offset, $count);
??? $value = substr($string, $offset);
??? ??? substr($string, $offset, $count) = $newstring;
??? substr($string, $offset, $count, $newstring); # 和前面一樣 ??? substr($string, $offset) = $newtail; ??? $string = "This is what you have"; ??? # you can test substrings with =~
??? if (substr($string, -10) =~ /pattern/) {
??? ??? print "Pattern matches in last 10 characters\n";
??? }
??? # substitute "at" for "is", restricted to first five characters
??? substr($string, 0, 5) =~ s/is/at/g; ??? # exchange the first and last letters in a string
$a = "make a hat";
??? ??? ??? (substr($a,0,1), substr($a,-1)) =
(substr($a,-1), substr($a,0,1));
??? print $a;
??? ??? take a ham
7.unpack函數 ??? # extract column with unpack
??? $a = "To be or not to be";
$b = unpack("x6 A6", $a);? # skip 6, grab 6
print $b;
??? ??? or not
|