Like Share Discussion Bookmark Smile

J.J. Huang   2021-03-17   Perl   瀏覽次數:

Perl - 第十四章 | Perl 格式化輸出

Perl 是一個非常強大的文本資料處理語言。
Perl 中可以使用 format 來定義一個模板,然後使用 write 按指定模板輸出資料。

Perl 格式化输出

Perl 格式化定義語法格式如下:

1
2
3
4
5
6
format FormatName =
fieldline
value_one, value_two, value_three
fieldline
value_one, value_two
.

參數解析:

  • FormatName :格式化名稱。
  • fieldline :一個格式行,用來定義一個輸出行的格式,類似 @,^,,| 這樣的字符。
  • value_one,value_two…… :資料行,用來向前面的格式行中插入值,都是perl的變量。
  • . :結束符號。

以下是一個簡單是格式化範例:

1
2
3
4
5
6
7
8
9
10
11
12
#!/usr/bin/perl

$text = "google morose dog";
format STDOUT =
first: ^<<<<< # 左邊對齊,字符長度為6
$text
second: ^<<<<< # 左邊對齊,字符長度為6
$text
third: ^< # 左邊對齊,字符長度為2,dog 最後一個 g 被截斷
$text
.
write

這將產生以下結果:

1
2
3
first: google  # 左邊對齊,字符長度為6
second: morose # 左邊對齊,字符長度為6
third: do # 左邊對齊,字符長度為2,dog 最後一個 g 被截斷

格式行(圖形行)語法

  • 格式行以 @ 或者 ^ 開頭,這些行不作任何形式的變量代換。
  • @ 字段(不要同數組符號 @ 相混淆)是普通的字段。
  • @,^ 後的 <, >,| 長度決定了字段的長度,如果變量超出定義的長度,那麼它將被截斷。
  • <, >,| 還分別表示,左對齊,右對齊,居中對齊。
  • ^ 字段用於多行文本塊填充。

值域格式

值域的格式,如下表所示:

格式 值域含義
@<<< 左對齊輸出
@>>> 右對齊輸出
@||| 中對齊輸出
@##.## 固定精度數字
@* 多行文本

每個值域的第一個字符是行填充符,當使用@字符時,不做文本格式化。
在上表中,除了多行值域@*,域寬都等於其指定的包含字符@在內的字符個數,例如:

1
@###.##

表示七個字符寬,小數點前四個,小數點後兩個。

範例如下:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
#!/usr/bin/perl

format EMPLOYEE =
===================================
@<<<<<<<<<<<<<<<<<<<<<< @<<
$name $age
@#####.##
$salary
===================================
.

select(STDOUT);
$~ = EMPLOYEE;

@n = ( "Ali", "Morose", "Jaffer" );
@a = ( 20, 30, 40 );
@s = ( 2000.00, 2500.00, 4000.000 );

$i = 0;
foreach (@n) {
$name = $_;
$age = $a[$i];
$salary = $s[ $i++ ];
write;
}

這將產生以下結果:

1
2
3
4
5
6
7
8
9
10
11
12
===================================
Ali 20
2000.00
===================================
===================================
Morose 30
2500.00
===================================
===================================
Jaffer 40
4000.00
===================================

格式變量

格式 說明
$~ ($FORMAT_NAME) 格式名字 $^ ($FORMAT_TOP_NAME) :當前的表頭格式名字存儲在
$% ($FORMAT_PAGE_NUMBER) 當前輸出的頁號
$= ($FORMAT_LINES_PER_PAGE) 每頁中的行數
$| ($FORMAT_AUTOFLUSH) 是否自動刷新輸出緩衝區存儲
$^L ($FORMAT_FORMFEED) 在每一頁(除了第一頁)表頭之前需要輸出的字符串存儲在

以下是一個簡單是使用 $~ 格式化的範例:

1
2
3
4
5
6
7
8
9
10
11
#!/usr/bin/perl

$~ = "MYFORMAT"; # 指定缺省文件變量下所使用的格式
write; # 輸出 $~ 所指定的格式

format MYFORMAT = # 定義格式 MYFORMAT
=================================
Text # MoroseDog自學
=================================
.
write;

這將產生以下結果:

1
2
3
4
5
6
=================================
Text # MoroseDog自學
=================================
=================================
Text # MoroseDog自學
=================================

如果不指定$~的情況下,會輸出名為STDOUT的格式:

1
2
3
4
5
6
7
8
9
10
#!/usr/bin/perl

write; # 不指定$~的情況下會尋找名為STDOUT的格式

format STDOUT =
~用~號指定的文字不會被輸出
----------------
STDOUT格式
----------------
.

這將產生以下結果:

1
2
3
----------------
STDOUT格式
----------------

以下範例我們通過添加報表頭部訊息來演示 $^ 或 $FORMAT_TOP_NAME 變量的使用:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
#!/usr/bin/perl

format EMPLOYEE =
===================================
@<<<<<<<<<<<<<<<<<<<<<< @<<
$name $age
@#####.##
$salary
===================================
.

format EMPLOYEE_TOP =
===================================
Name Age
===================================
.

select(STDOUT);
$~ = EMPLOYEE;
$^ = EMPLOYEE_TOP;

@n = ( "Ali", "Morose", "Jaffer" );
@a = ( 20, 30, 40 );
@s = ( 2000.00, 2500.00, 4000.000 );

$i = 0;
foreach (@n) {
$name = $_;
$age = $a[$i];
$salary = $s[ $i++ ];
write;
}

這將產生以下結果:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
===================================
Name Age
===================================
===================================
Ali 20
2000.00
===================================
===================================
Morose 30
2500.00
===================================
===================================
Jaffer 40
4000.00
===================================

我們也可以使用 $% 或 $FORMAT_PAGE_NUMBER 為報表設置分頁:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
#!/usr/bin/perl

format EMPLOYEE =
===================================
@<<<<<<<<<<<<<<<<<<<<<< @<<
$name $age
@#####.##
$salary
===================================
.

# 添加分页 $%
format EMPLOYEE_TOP =
===================================
Name Age Page @<
$%
===================================
.

select(STDOUT);
$~ = EMPLOYEE;
$^ = EMPLOYEE_TOP;

@n = ( "Ali", "Morose", "Jaffer" );
@a = ( 20, 30, 40 );
@s = ( 2000.00, 2500.00, 4000.000 );

$i = 0;
foreach (@n) {
$name = $_;
$age = $a[$i];
$salary = $s[ $i++ ];
write;
}

這將產生以下結果:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
===================================
Name Age Page 1
===================================
===================================
Ali 20
2000.00
===================================
===================================
Morose 30
2500.00
===================================
===================================
Jaffer 40
4000.00
===================================

頁面上的行數

你可以使用特殊變量$ =(或$ FORMAT_LINES_PER_PAGE)設置每頁的行數,預設情況下,$ =將為60。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
#!/usr/bin/perl

format EMPLOYEE =
===================================
@<<<<<<<<<<<<<<<<<<<<<< @<<
$name $age
@#####.##
$salary
===================================
.

# 添加分页 $%
format EMPLOYEE_TOP =
===================================
Name Age Page @<
$%
===================================
.

select(STDOUT);
$~ = EMPLOYEE;
$^ = EMPLOYEE_TOP;
$= = 10;

@n = ( "Ali", "Morose", "Jaffer" );
@a = ( 20, 30, 40 );
@s = ( 2000.00, 2500.00, 4000.000 );

$i = 0;
foreach (@n) {
$name = $_;
$age = $a[$i];
$salary = $s[ $i++ ];
write;
}

這將產生以下結果:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
===================================
Name Age Page 1
===================================
===================================
Ali 20
2000.00
===================================

===================================
Name Age Page 2
===================================
===================================
Morose 30
2500.00
===================================

===================================
Name Age Page 3
===================================
===================================
Jaffer 40
4000.00
===================================

註:當設定的行數無法放全部內容就會被分配到下一頁

定義報告頁腳

雖然$ ^或 $FORMAT_TOP_NAME 包含當前頁眉格式的名稱,但是沒有相應的機制可以自動為頁腳執行相同的操作。如果你使用固定大小的頁腳,則可以通過在每個write()之前檢查變量$-或 $FORMAT_LINES_LEFT來獲取頁腳,並在必要時使用定義如下的另一種格式自己打印頁腳:

1
2
3
4
format EMPLOYEE_BOTTOM =
End of Page @<
$%
.

註:這邊我試過使用 $- 去做頁腳的輸出,沒有輸出成功…。

輸出到其它文件

預設情況下函數write將結果輸出到標準輸出文件STDOUT,我們也可以使它將結果輸出到任意其它的文件中。最簡單的方法就是把文件變量作為參數傳遞給write,如:

1
2
write(MYFILE);
以上程式碼write就用缺省的名為MYFILE的打印格式輸出到文件MYFILE中。

但是這樣就不能用$~變量來改變所使用的打印格式。系統變量$~只對預設文件變量起作用,我們可以改變預設文件變量,改變$~,再調用write。

1
2
3
4
5
6
7
8
9
10
11
12
13
#!/usr/bin/perl

if ( open( MYFILE, ">tmp" ) ) {
$~ = "MYFORMAT";
write MYFILE; # 含文件變量的輸出,此時會打印與變量同名的格式,即MYFILE。 $~裡指定的值被忽略。

format MYFILE = # 與文件變量同名
=================================
輸入到文件中
=================================
.
close MYFILE;
}

這將產生以下結果:

1
2
3
4
$ cat tmp
=================================
輸入到文件中
=================================

我們可以使用select改變預設文件變量時,它返回當前預設文件變量的內部表示,這樣我們就可以建立子程序,按自己的想法輸出,又不影響程序的其它部分。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
#!/usr/bin/perl

if ( open( MYFILE, ">>tmp" ) ) {
select(MYFILE); # 使得預設文件變量的打印輸出到MYFILE中
$~ = "OTHER";
write; # 預設文件變量,打印到select指定的文件中,必使用$~指定的格式 OTHER

format OTHER =
=================================
使用定義的格式輸入到文件中
=================================
.
close MYFILE;
}

這將產生以下結果:

1
2
3
4
5
6
7
$ cat tmp
=================================
輸入到文件中
=================================
=================================
使用定義的格式輸入到文件中
=================================

註:以上參考了
Tutorialspoint, Perl - Formats