Lessons VI : Nhập vào từ STDIN

Perl

6.1 Nhập vào từ STDIN

Việc đọc từ lối vào chuẩn (thông qua tước tiệu tệp STDIN-viết tắt của Standard Input trong Perl) thì thật dễ dàng. Chúng ta đã làm việc này với toán tử <STDIN>. Việc dùng toán tử này trong ngữ cảnh vô hướng trả về cho bạn bạn một dòng của cái đang được nhập vào, hoặc undef nếu không còn dòng nào nữa, giống như:

$a = <STDIN>; # đọc dòng tiếp theo

Việc dùng toán tử này trong ngữ cảnh mảng sẽ cho bạn tất cả các dòng còn lại như một danh sách – mỗi phần tử của danh sách này là một dòng, bao gồm cả ký tự xuống dòng mới của nó. Chúng ta đã thấy điều này trước đây, nhưng xem như đây là bài ôn tập, nó có thể trông như một cái gì đó tựa như thế này:

@a = <STDIN>;

Một cách điển hình, một trong những điều bạn muốn làm là đọc tất cả các dòng một lúc, và làm điều gì đó trên mỗi dòng. Một cách chung để làm điều này là:

while ($_ = <STDIN>) {

# xử lí $_ tại đây (cho từng dòng)

}

Cứ mỗi khi một dòng được đọc vào, <STDIN> lại trả về một giá trị đúng (true), cho nên chu trình tiếp tục thực hiện. Khi <STDIN> không còn dòng nào để đọc nữa thì nó trả về undef, tương đương với giá trị sai (false), kết thúc chu trình.

Việc đọc một giá trị vô hướng từ <STDIN> vào $_ và dùng giá trị đó làm biểu thức điều khiển cho chu trình (như trong ví dụ vừa rồi) thường hay xuất hiện đến mức Perl có hẳn một cách viết tắt cho nó. Bất kì khi nào việc kiểm tra chu trình chỉ bao gồm một toán tử đưa vào (cái gì đó tựa như <…>), thì Perl tự động sao dòng được đọc vào sẽ lưu trong biến $_.

while ($_ = <STDIN>) { # giống while ($_ = <STDIN>)

chop; # giống chop($_)

# các phép toán khác với $_ ở đây

}

Vì biến $_ là mặc định cho nhiều phép toán nên bạn có thể tiết kiệm khá nhiều cú gõ phím theo cách này.

6.2 Nhập vào từ toán tử “hình thoi”

Một cách khác để đọc dữ liệu vào là dùng toán tử hình thoi: <>. Toán tử này giống như <STDIN> ở chỗ nó trả về một dòng riêng trong ngữ cảnh vô hướng (undef nếu tất cả các dòng này đã được đọc), hay tất cả các dòng còn lại nếu được dùng trong ngữ cảnh mảng. Tuy nhiên, khác với <STDIN>, toán tử hình thoi lấy dữ liệu từ tệp hay các tệp được xác định trên dòng lệnh được gọi trong chương trình Perl. Chẳng hạn, nếu bạn có một chương trình mang tên kitty, bao gồm:

#!/usr/bin/perl

while (<>) {

print $_;

}

và nếu bạn gọi kitty với: kitty file1 file2 file3 thì toán tử hình thoi sẽ đọc từng dòng của file1 tiếp theo là từng dòng của file2 và file3 lần lượt, và cuối cùng trả về undef khi tất cả các dòng đã được đọc hết.

Như bạn có thể thấy, kitty làm việc giống như cat (một lệnh của Linux), gửi tất cả các dòng của tệp có tên ra thiết bị xuất chuẩn (STDOUT) theo tuần tự. Nếu, giống cat, bạn không xác định bất kì tên tệp nào trên dòng lệnh thì toán tử hình thoi sẽ tự động đọc từ STDIN.

Về mặt kĩ thuật, toán tử hình thoi không nhìn y nguyên vào các tham số của dòng lệnh – nó làm việc từ mảng @ARGV. Mảng này là một mảng đặc biệt được bộ thông dịch Perl đặt sẵn là một danh sách các tham số của dòng lệnh. Mỗi tham số dòng lệnh được bỏ đi sau khi Perl đã lấy các chuyển mạch dòng lệnh của nó để đưa vào một phần tử tách biệt của mảng @ARGV. Bạn có thể xử lý danh sách này theo bất kì cách nào bạn muốn. Bạn thậm chí có thể đặt mảng này bên trong chương trình của mình, và khi đó toán tử hình thoi làm việc trên danh sách mới thay vì các tham số của dòng lệnh, như thế này:

#!/usr/bin/perl

@ARGV = (“aaa”, “bbb”, “ccc”);

while (<>) {    # xu ly cac file aa, bbb va ccc

print “This line is: $_”;

}

Trong Chương 10:Tước hiệu tệp và và kiểm tra tệp, chúng ta sẽ tìm hiểu cách mở và đóng các tệp xác định vào thời điểm xác định, tuy nhiên các làm trong ví dụ trên vẫn dùng được trong một số chương trình Perl của bạn.

6.3 Đưa ra STDOUT

Perl dùng các toán tử print và printf để ghi/xuất dữ liệu ra STDOUT. Ta hãy xem cách chúng được dùng.

6.3.1 Dùng print cho cách xuất thông thường

Chúng ta đã dùng print để hiển thị văn bản ra STDOUT (thường được hiển là màn hình). Ta hãy mở rộng thêm một chút.

Toán tử print nhận một danh sách các xâu, và gửi lần lượt từng xâu ra STDOUT. Điều có thể không hiển nhiên là ở chỗ print thực sự chỉ là toán tử danh sách, và trả về một giá trị giống như bất kì toán tử danh sách nào khác. Nói cách khác:

$a = print (“xin chao”, “moi nguoi”, “\n”);

sẽ là một cách khác để nói “xin chao moi nguoi”. Giá trị trả lại của print là một giá trị đúng hay sai, chỉ ra sự thành công của việc in. Nó gần như bao giờ cũng thành công, trừ phi bạn gặp lỗi vào/ra nào đó, cho nên $a trong trường hợp này sẽ gần như bao giờ cũng là 1.

Đôi khi, bạn sẽ cần bổ sung thêm các dấu ngoặc vào print như được nêu trong ví dụ này, đặc biệt nếu cái đầu tiên mà bạn muốn in bắt đầu với một dấu mở ngoặc tròn, như trong:

print (2+3), “xin chao”;   # sai! in 5, bỏ qua “xin chao”

print ((2+3), “xin chao”); # đúng! in “5xin chao”

print 2+3, “xin chao”;     # cũng đúng! in “5xin chao”

6.3.2 Dùng printf xuất dữ liệu theo định dạng

Bạn có thể muốn có một chút ít kiểm soát với dữ liệu in ra hơn là khả năng print cung cấp. Trong thực tế, bạn có thể quen với cách xuất dữ liệu có định dạng của hàm printf trong C. Perl cung cấp một phép toán tương ứng với cùng tên.

Toán tử printf nhận một danh sách tham số (được bao trong dấu ngoặc tròn tuỳ chọn, tương tự như đối với toán tử print). Tham số thứ nhất là một xâu kiểm soát định dạng, xác định cách in các đối còn lại. Nếu bạn còn chưa quen thuộc với hàm printf chuẩn, thì bạn xem hướng dẫn trong man printf, và nếu có thể bạn nên xem ở chương 3 của quyển sách Programming Perl. Tuy nhiên, hãy xem một ví dụ:

printf “%15s %5d %10.2f\n”, $s, $n, $r;

toán tử printf trong ví dụ ở trên sẽ in ra xâu $s trong một trường 15 kí tự, rồi đến dấu cách, rồi đến $n xem như một số nguyên trong trường 5 kí tự, rồi lại đến một dấu cách khác, tiếp theo đến lượt $r được tin như giá trị dấu phẩy động với 2 vị trí thập phân trong một trường 10 kí tự, và cuối cùng là một dấu xuống dòng mới.

 

6.4 Bài tập

Bạn hãy viết một chương trình hoạt động như lệnh cat của Linux (xem ví dụ trong phần 6.2) nhưng thứ tự các dòng khi in sẽ được đảo ngược (dòng nhập vào sau cùng sẽ được in ra trước tiên và dòng nhập vào trước tiên sẽ được in ra sau cùng-tương tự như lệnh tac trên một số hệ thống).

Ví dụ: có 3 tệp A, B, C. Tệp A chứa 2 dòng 1 và 2, tệp B chứa 3 dòng 3, 4 và 5, tệp C chứa 1 dòng 6. Kết quả được in sẽ là:

6

5

4

3

2

1

Bạn hãy sửa lại chương trình ở bài tập một sao cho mội dung mỗi tệp (tên tệp được nhận từ danh sách các tham số dòng lệnh) sẽ được in theo thứ tự đảo ngược. Nghĩa là, với 3 tệp A, B, C như trên, kết quả sau khi in sẽ là:

2

1

5

4

3

6

Bạn hãy viết 1 chương trình đọc vào một danh sách các xâu và in danh sách các xâu mới đọc (các xâu được canh lề phải 20 ký tự khi in).

Hãy hãy sửa lại chương trình ở trên sao cho chương trình in ra các xâu được canh lề phải với n ký tự (với n được nhập vào bởi người dùng).

(Sưu tầm từ diễn đàn tin học)


Thiết kế bởi Phạm Nguyễn Bảo Nguyên
GC Com 2005

  1. Leave a comment

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out / Change )

Twitter picture

You are commenting using your Twitter account. Log Out / Change )

Facebook photo

You are commenting using your Facebook account. Log Out / Change )

Google+ photo

You are commenting using your Google+ account. Log Out / Change )

Connecting to %s

%d bloggers like this: