第十章 格式化輸出
by
flamephoenix
?
一、定義打印格式 二、顯示打印格式 三、在打印格式中顯示值
? 1、通用的打印格式
? 2、格式和局域變量
? 3、選擇值域格式
? 4、輸出值域字符 四、輸出到其它文件 五、分頁 六、格式化長字符串 七、用printf格式化輸出
????我們已經(jīng)見過用print函數(shù)將原始的未格式化的文本輸出到文件,本章講述如何用函數(shù)write和打印格式來生成格式化的輸出。 二、顯示打印格式
????打印格式的顯示有兩步: ????
1、將系統(tǒng)變量$~設(shè)成所要使用的格式 ????
2、調(diào)用函數(shù)write ????例如:
1 : #!/usr/local/bin/perl 2 : 3 : $~ = "MYFORMAT"; 4 :
write; 5 : 6 : format MYFORMAT = 7 :
=================================== 8 : Here is the text I want to
display. 9 : =================================== 10: .
????結(jié)果輸出如下:
$ program =================================== Here is the text
I want to display. =================================== $
????如果不用$~指定打印格式,Perl解釋器就假定要使用的格式名與要寫入的文件變量同名,在本例中,如果不指定使用MYFORMAT,則Perl解釋器試圖使用名為STDOUT的打印格式。 三、在打印格式中顯示值 ????我們使用打印格式的主要原因當(dāng)然是格式化存貯在簡單變量或數(shù)組變量中的值從而生成可讀性好的輸出,這一目的用“值域”來實現(xiàn)。每個值域指定一個值,如變量或表達(dá)式,調(diào)用write函數(shù)時,該值就以值域指定的格式顯示。 1、通用的打印格式 ????打印格式的一個缺點是定義中包含了變量名,例如:
format MYFORMAT
= ========================================================== The
winning number is
@<<<<<<! $winnum ========================================================== .
????當(dāng)調(diào)用write輸出此格式時,必須記著它使用了變量$winnum。用子程序和局域變量就可以創(chuàng)建更通用的打印格式。下例從STDIN輸入一個文件并輸出五個出現(xiàn)頻率最高的字母及出現(xiàn)次數(shù)。
1 : #!/usr/local/bin/perl 2 : 3 : while ($line = )
{ 4 : ? $line =~ tr/A-Z/a-z/; 5 : ? $line =~
s/[^a-z]//g; 6 : ? @letters = split(//, $line); 7 : ?
foreach $letter (@letters) { 8 : ? ? $lettercount{$letter} +=
1; 9 : ? } 10: } 11: 12: $~ = "WRITEHEADER"; 13:
write; 14: $count = 0; 15: foreach $letter (reverse sort
occurrences 16: ? ? ? (keys(%lettercount))) { 17:
? &write_letter($letter, $lettercount{$letter}); 18: ?
last if (++$count == 5); 19: } 20: 21: sub occurrences
{ 22: ? $lettercount{$a} <=> $lettercount{$b}; 23:
} 24: sub write_letter { 25: ? local($letter, $value) =
@_; 26: 27: ? $~ = "WRITELETTER"; 28: ?
write; 29: } 30: format WRITEHEADER = 31: The five most
frequently occurring letters are: 32: . 33: format WRITELETTER
= 34: ? @: @<<<<<< 35: ? $letter,
$value 36: .
????運行結(jié)果如下:
$ program
This is a test file.
This test file contains some input.
The quick brown fox jumped over the lazy dog.
^D
The five most frequently occurring letters are:
t: 10
e: 9
i: 8
s: 7
o: 6
$
2、格式和局域變量 ????在上例中,你可能已經(jīng)注意到子程序write_letter調(diào)用write輸出字母及其出現(xiàn)次數(shù),即使格式定義在子程序外部仍能正常工作。在第17行中將字母及其出現(xiàn)次數(shù)傳遞給該子程序,在子程序中,打印格式使用局域變量$letter和$value,這樣保證了在foreach循環(huán)中每次輸出當(dāng)前的字母和值。 ????然而要注意的是,使用my定義的局域變量要求格式定義在子程序內(nèi)部,否則就不會輸出,因此,用write輸出的局域變量一定要用local定義。(local和my詳見《子程序》一章) ????注:Perl4中沒有my函數(shù),故不會有此問題。 3、選擇值域格式 ????我們已經(jīng)知道了打印格式和write函數(shù)怎么工作,現(xiàn)在來看看值域的格式,見下表:
格式 |
值域含義 |
@<<< |
左對齊輸出 |
@>>> |
右對齊輸出 |
@||| |
中對齊輸出 |
@##.## ? |
固定精度數(shù)字 ? |
@* |
多行文本 |
????每個值域的第一個字符是行填充符,當(dāng)使用@字符時,不做文本格式化。對文本的格式化稍后來講。 ????在上表中,除了多行值域@*,域?qū)挾嫉扔谄渲付ǖ陌址鸃在內(nèi)的字符個數(shù),例如: ????
@###.## ????表示七個字符寬,小數(shù)點前四個,小數(shù)點后兩個。 4、輸出值域字符 ????在打印格式里,特定字符如@、<和>被看作值域定義,那么如何將它們輸出呢?方法如下:
format SPECIAL = This line contains the special character
@. "@" .
四、輸出到其它文件 ????缺省地,函數(shù)write將結(jié)果輸出到標(biāo)準(zhǔn)輸出文件STDOUT,我們也可以使它將結(jié)果輸出到任意其它的文件中。最簡單的方法就是把文件變量作為參數(shù)傳遞給write,如: ????
write
(MYFILE); ????這樣,write就用缺省的名為MYFILE的打印格式輸出到文件MYFILE中,但是這樣就不能用$~變量來改變所使用的打印格式。系統(tǒng)變量$~只對缺省文件變量起作用,我們可以改變?nèi)笔∥募兞浚淖?~,再調(diào)用write,例如: ????
select (MYFILE); ???? $~ =
"MYFORMAT"; ????
write; ????當(dāng)select改變?nèi)笔∥募兞繒r,它返回當(dāng)前缺省文件變量的內(nèi)部表示,這樣我們就可以創(chuàng)建子程序,按自己的想法輸出,又不影響程序的其它部分,如下:
sub write_to_stdout { ? local ($savefile,
$saveformat); ? $savefile = select(STDOUT); ?
$saveformat = $~; ? $~ = "MYFORMAT"; ? write; ? $~ =
$saveformat; ? select($savefile); }
五、分頁 ????在輸出到打印機時,可以在每頁頂部輸出相應(yīng)的信息,這樣的特殊文本叫頁眉。定義頁眉實際上就是定義名為filename_TOP的打印格式,例如給標(biāo)準(zhǔn)輸出文件定義頁眉如下: ????
format STDOUT_TOP = ???? Consolidated Widgets Inc.
1994 Annual Report ????
. ????在頁眉的定義中也可以包含值域,頁眉中經(jīng)常使用的一個特殊值是當(dāng)前頁碼,存貯在系統(tǒng)變量$%中,如: ????
format STDOUT_TOP = ???? Page
@<<. ???? $% ????
. ????我們也可以通過改變系統(tǒng)變量$^改變定義頁眉的打印格式名,與$~一樣,$^只對當(dāng)前缺省文件起作用,因此可以與select函數(shù)結(jié)合使用。 ????缺省情況下,每頁長度為60行,可以通過改變$=來改變頁長,如: ????
$= = 66;
#頁長設(shè)為66行 ????此賦值語句必須出現(xiàn)在第一個write語句前。 ????注:一般使用分頁機制時不用print函數(shù),因為當(dāng)用write輸出時,Perl解釋器跟蹤每頁的當(dāng)前行號。如果必須使用print而又不打亂頁計數(shù),可以調(diào)整系統(tǒng)變量$-。$-的含義是當(dāng)前行到頁末之間的行數(shù),當(dāng)$-達(dá)到零時,就開始新的一頁,調(diào)整方法如: ????
print ("Here is a line of output\n"); ???? $- -=
1; 六、格式化長字符串 ????我們已經(jīng)學(xué)過值域@*可以輸出多行文本,但它完全將字符串原樣輸出,不加以格式化。在Perl中對長字符串(包含換行)進(jìn)行格式化的值域定義很簡單,只需把打頭的@字符換成^就行了,這種文本格式化中,Perl解釋器在一行中放置盡可能多的單詞。每當(dāng)輸出一行文本,被輸出的子串就從變量中刪除,再次在域值中使用該變量就把剩下的字符串繼續(xù)按格式輸出。當(dāng)內(nèi)容已輸出完畢,該變量就成了空串,再輸出就會輸出空行,為避免輸出空行,可以在值域格式行首加一個~字符。見下例:
1 : #!/usr/local/bin/perl 2 : 3 : @quotation =
<STDIN>; 4 : $quotation = join("", @quotation); 5 : $~ =
"QUOTATION"; 6 : write; 7 : 8 : format QUOTATION = 9 :
Quotation for the day: 10: ----------------------------- 11:
~?
^<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<< 12:
$quotation 13: ~?
^<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<< 14:
$quotation 15: ~?
^<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<< 16:
$quotation 17: ----------------------------- 18: .
????運行結(jié)果如下:
$ program Any sufficiently advanced programming language is
indistinguishable from magic. ^D Quotation for the
day: ----------------------------- ? ?Any sufficiently
advanced programming language is ? ?indistinguishable from
magic. ----------------------------- $
????如果把打印格式中行首的~字符去掉,上面的輸出結(jié)果中就會多一行空行。很明顯,當(dāng)字符串長度不明確時,這種用法很不方便,原因就在于它指明了輸出的行數(shù)上限,超過這一上限的字符就不會被輸出,解決方法很簡單,就是在域值格式行首加兩個~字符,這樣就會持續(xù)按格式輸出文本直到輸出完畢,用此方法把上述程序改寫如下:
1 : #!/usr/local/bin/perl 2 : 3 : @quotation =
<STDIN>; 4 : $quotation = join("", @quotation); 5 : $~ =
"QUOTATION"; 6 : write; 7 : 8 : format QUOTATION = 9 :
Quotation for the day: 10: ----------------------------- 11: ~~
^<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<< 12:
$quotation 13: ----------------------------- 14: .
????這樣運行結(jié)果相同。 七、用printf格式化輸出 ????還有一種容易掌握和使用的格式化輸出函數(shù),那就是printf,它與C語言中的printf基本上是相同的。printf有兩個參數(shù),一個是字符串,其中含有一個或多個域值形式,另一個是與各域值相對應(yīng)的變量值按一定格式替換,如: ????
printf("The number I want to print is %d.\n",
$number); ????各種域值形式如下表:
域值 ? |
含義 |
%c |
單個字符 |
%d |
十進(jìn)制整數(shù) |
%e |
科學(xué)計數(shù)法形式的浮點數(shù) ? |
%f |
普通形式(定點)浮點數(shù) |
%g |
緊縮形式浮點數(shù) |
%o |
八進(jìn)制整數(shù) |
%s |
字符串 |
%u |
無符號整數(shù) |
%x |
十六進(jìn)制整數(shù) |
????一些使用細(xì)節(jié)如下:
1、在格式d、o、u或x中,如果整數(shù)值較大或可能較大,可加個l字符,意為長整型,如%ld。 2、%字符后加正整數(shù)表示該域的最小寬度,如果輸出結(jié)果寬度不足,則向右對齊,前面用空格補足,如果該正整數(shù)以數(shù)字0打頭,則補足字符為0。若%字符后為負(fù)整數(shù),則結(jié)果向右對齊。 3、浮點數(shù)域值(%c、%f和%g)中可以指定小數(shù)點前后的寬度,如%8.3f意為總寬度為8個字符,小數(shù)點后(即小數(shù)部分)為3個字符,多出的小數(shù)部分四舍五入。 4、在整數(shù)、字符或字符串的值域中使用如上的小數(shù)形式n.m,整數(shù)部分n為總寬度,小數(shù)部分m為輸出結(jié)果的最大寬度,這樣就保證了輸出結(jié)果前至少有n-m個空格。
|