Thứ Hai, 1 tháng 2, 2016

Sách Perl Tiếng Việt



Tạo chủ đề mới Chủ đề này đã bị khóa, bạn không thể sửa những bài viết của mình hay trả lời bài viết thêm nữa.  [ 18 bài viết ]  Chuyển đến trang 1, 2  Trang kế tiếp
Người gửi Nội dung
 Tiêu đề bài viết: Sách Perl Tiếng Việt
Gửi bàiĐã gửi: T.Năm Tháng 11 22, 2007 8:49 am 
Đóng góp tích cực
Hình đại diện của thành viên

Ngày tham gia: T.Tư Tháng 11 21, 2007 1:22 pm
Bài viết: 264
Đến từ: Viet Nam
Nhocyeu_ufa lượm lặt gần xa

Lời giới thiệu

Cuốn sách này nói về gì

1: Giới thiệu
Lịch sử của Perl
Mục đích của Perl
Những điều có sẵn
Hỗ trợ
Các khái niệm cơ bản
Dạo qua Perl
Bài tập

2:Dữ liệu vô hướng
Dữ liệu vô hướng là gì?
Số
Xâu
Toán tử
Biến vô hướng
Toán tử trên biến vô hướng
như giá trị vô hướng
Đưa ra với print()
Giá trị undef
Bài tập

3: Dữ liệu mảng và danh sách
Mảng là gì?
Biểu diễn hằng kí hiệu
Biến
Toán tử
Vô hướng và ngữ cảnh mảng
như một mảng
Nội suy biến thiên của mảng
Bài tập

4: Cấu trúc điều khiển
Khối câu lệnh
Câu lệnh if/unless
Câu lệnh while/until
Câu lệnh for
Câu lệnh foreach
Bài tập

5: Mảng kết hợp
Mảng kết hợp là gì?
Biến mảng kết hợp
Biểu diễn hằng kí hiệu cho mảng kết hợp
Toán tử mảng kết hợp
Bài tập

6: Vào/ra cơ sở
Đưa vào từ STDIN
Đưa vào từ toán tử hình thoi
Đưa ra STDOUT
Bài tập

7: Biểu thức chính qui
Khái niệm về biểu thức chính qui
Cách dùng đơn giản về biểu thức chính qui
Mẫu
Nói thêm về toán tử đối sánh
Phép thế
Các toán tử split(0 và join()
Bài tập

8: Hàm
Các hàm hệ thống và người dùng
Định nghĩa hàm người dùng
Gọi hàm người dùng
Cho lại giá trị
Đối
Biến cục bộ trong hàm
Bài tập

9: Các cấu trúc điều khiển
Toán tử last
Toán tử next
Toán tử redo
Khối có nhãn
Bộ sửa đổi biểu thức
&&, || và ?: xem như các cấu trúc điều khiển
Bài tập

10: Giải quyết tệp và kiểm thử tệp
Tước hiệu tệp là gì?
Mở và đóng một tước hiệu tệp
Một chút tiêu khiển: die()
Dùng tước hiệu tệp
Kiểm tra tệp -x
Toán tử stat() và lstat()
Dùng _Filehandle
Bài tập

11: Định dạng
Định dạng là gì?
Xác định một định dạng
Gọi một định dạng
Nói thêm về Fieldholder
Định dạng đỉnh trang
Đổi giá trị mặc định cho định dạng
Bài tập

12: Thâm nhập danh mục
Đi vòng quanh cây danh mục
Globbing
Giải quyết danh mục
Mở và đóng bộ giải quyết danh mục
Đọc bộ giải quyết danh mục
Bài tập

13: Thao tác tệp và danh mục
Loại bỏ tệp
Đổi tên tệp
Tạo ra tên thay phiên cho một tệp (liên kết)
Tạo ra và xoá danh mục
Sửa đổi phép dùng
Sửa đổi quyền dùng
Sửa đổi thời hạn
Bài tập

14: Quản lí tiến trình
Dùng system() và exec()
Dùng Backquotes
Dùng Proceses và Filehandles
Dùng folk
Tóm tắt về các phép toán tiến trình
Gửi và nhận tín hiệu
Bài tập

15: Biến đổi dữ liệu khác
Tìm xâu con
Trích và thay thế xâu con
Định dạng dữ liệu bằng sprintf()
Sắp xếp cao cấp
Chuyển tự
Bài tập

16: Thâm nhập cơ sở dữ liệu hệ thống
Lấy mật hiệu và thông tin nhóm
Đóng và mở gói dữ liệu nhị phân
Lấy thông tin mạng
Lấy thông tin khác
Bài tập

17: Thao tác cơ sở dữ liệu người dùng
Cơ sở dữ liệu DBM và mảng DBM
Mở và đóng mảng DBM
Dùng mảng DBM
Cơ sở dữ liệu thâm nhập ngẫu nhiên chiều dài cố định
Cơ sở dữ liệu chiều dài biến thiên (văn bản)
Bài tập

18: Chuyển các ngôn ngữ khác sang Perl
Chuyển Chương trình awk sang Perl
Chuyển Chương trình sed sang Perl

Bài tập

A: Trả lời bài tập

B: Cơ sở về nối mạng
Mô hình chỗ cắm
Khách mẫu
Bộ phục vụ mẫu

C: Những chủ đề chưa đề cập tới
Bộ gỡ lỗi
Dòng lệnh
Các toán tử khác
Nhiều, nhiều hàm nữa
Nhiều, nhiều biến đặt sẵn nữa
Xâu ở đây
return (từ chương trình con)
Toán tử eval (và s///e)
Thao tác bảng kí hiệu với *FRED
Toán tử goto
Toán tử require
Thư viện
Perl bản 5.0 Goodies
Chỉ mục

_________________
..................................................................................
nhocyeu_ufa
..................................................................................

Hình ảnhHình ảnh


album1 - hình chụp với Ubuntu
album2 - ảnh cá nhân & bên ngoài


Sửa lần cuối bởi nhocyeu_ufa vào ngày T.Năm Tháng 11 22, 2007 8:51 am với 1 lần sửa.

Đầu trang
 Xem thông tin cá nhân  
 
Gửi bàiĐã gửi: T.Năm Tháng 11 22, 2007 9:10 am 
Đóng góp tích cực
Hình đại diện của thành viên

Ngày tham gia: T.Tư Tháng 11 21, 2007 1:22 pm
Bài viết: 264
Đến từ: Viet Nam
Nhocyeu_ufa lượm lặt gần xa

1

Giới thiệu

Lịch sử Perl
Perl là cách viết tắt cho “Practical Extraction and Report Language” Ngôn ngữ báo cáo và trích rút thực hành, mặc dầu nó cũng còn được gọi là “Pathologically Eclectic Rubbish Lister” - Bộ làm danh sách chiết trung bậy bạ và bệnh hoạn. Chẳng ích gì mà biện minh xem cách gọi nào đúng hơn, vì cả hai đều được Larry Wall, người sáng tạo và kiến trúc sư chính, người cài đặt và bảo trì của Perl chấp nhận. Ông ấy đã tạo ra Perl khi cố gắng sản xuất ra một số báo cáo từ một cấp bậc các tệp kiểu như thư người dùng mạng Usenet về hệ thống báo lỗi, và lệnh awk làm xì hết hơi. Larry, một người lập trình lười biếng, quyết định thanh toán vấn đề này bằng một công cụ vạn năng mà anh có thể dùng ít nhất cũng ở một nơi khác. Kết quả là bản đầu tiên của Perl.
Say khi chơi với bản đầu này của Perl một chút, thêm chất liệu đây đó, Larry đưa nó cho cộng đồng độc giả Usenet, thường vẫn được gọi là “the Net”. Người dùng thuộc toán phù du nghèo khó về hệ thống trên toàn thế giới (quãng độ chục nghìn người) đưa lại cho anh phản hồi, hỏi cách làm thế này thế kia, việc này việc khác, nhiều điểm mà Larry chưa bao giờ mường tượng ra về việc giải quyết cho Perl nhỏ bé của mình cả.
Nhưng kết quả là Perl trưởng thành, trưởng thành và trưởng thành thêm nữa, và cũng cùng tỉ lệ như lõi của UNIX. (với bạn là người mới, toàn bộ lõi UNIX được dùng chỉ khít vào trong 32K! Và bây giờ chúng ta may mắn nếu ta có thể có được nó dưới một vài mega.) Nó đã trưởng thành trong các tính năng. Nó đã trưởng thành trong tính khả chuyển. Điều mà có thời là một ngôn ngữ tí tẹo bây giờ đã có tài liệu sử dụng 80 trang, một cuốn sách của Nutshell 400 trang, một nhóm tin Usenet với 40 nghìn thuê bao, và bây giờ là đoạn giới thiệu nhẹ nhàng này.
Larry vẫn là người bảo trì duy nhất, làm việc trên Perl ngoài giờ khi kết thúc công việc thường ngày của mình. Và Perl thì vẫn phát triển.
Một cách đại thể thì lúc mà cuốn sách này đạt tới điểm dừng của nó, Larry sẽ đưa ra bản Perl mới nhất, bản 5.0, hứa hẹn có một số tính năng thường hay được yêu cầu, và được thiết kế lại từ bên trong trở ra. (Larry bảo tôi rằng không còn mấy dòng lệnh từ lần đưa ra trước, và số ấy cứ ngày càng ít đi mỗi ngày.) Tuy nhiên, cuốn sách này đã được thử với Perl bản 4.0 (lần đưa ra gần đây nhất khi tôi viết điều này). Mọi thứ ở đây đều sẽ làm việc với bản 5.0 và các bản sau của Perl. Trong thực tế, chương trình Perl 1.0 vẫn làm việc tốt với những bản gần đây, ngoại trừ một vài thay đổi lạ cần cho sự tiến bộ.

Mục đích của Perl
Perl được thiết kế để trợ giúp cho người dùng UNIX với những nhiệm vụ thông dụng mà có thể rất nặng nề hay quá nhậy cảm với tính khả chuyển đối với trình vỏ, và cũng quá kì lạ hay ngắn ngủi hay phức tạp để lập trình trong C hay một ngôn ngữ công cụ UNIX nào khác.
Một khi bạn trở nên quen thuộc với Perl, bạn có thể thấy mình mất ít thời gian để lấy được trích dẫn trình vỏ (hay khai báo C) đúng, và nhiều thời gian hơn để đọc tin trên Usenet và đi trượt tuyết trên đồi; vì Perl là một công cụ lớn tựa như chiếc đòn bẩy. Các cấu trúc chặt chẽ của Perl cho phép bạn tạo ra (với tối thiểu sự om sòm nhặng sị) một số giải pháp có ưu thế rất trần lặng hay những công cụ tổng quát. Cũng vậy, bạn có thể lôi những công cụ này sang công việc tiếp, vì Perl là khả chuyển cao độ và lại có sẵn, cho nên bạn sẽ có nhiều thời gian hơn để đọc tin Usenet và trượt tuyết.
Giống như mọi ngôn ngữ, Perl có thể “chỉ viết” - tức là có thể viết ra chương trình mà không thể nào đọc được. Nhưng với sự chú ý đúng đắn, bạn có thể tránh được sự kết tội thông thường này. Quả thế, đôi khi Perl trông như nổi tiếng với những cái không quen thuộc, nhưng với người lập trình đã thạo Perl, nó tựa như những dòng có tổng kiểm tra với một sứ mệnh trong cuộc đời. Nếu bạn tuân theo những hướng dẫn của cuốn sách này thì chương trình của bạn sẽ dễ đọc và dễ bảo trì, và chúng có lẽ sẽ không thắng trong bất kì cuộc tranh luận Perl khó hiểu nào.

Tính sẵn có
Nếu bạn nhận được
Perl: not found
khi bạn thử gọi Perl từ lớp vỏ thì người quản trị hệ thống của bạn cũng chẳng lên cơn sốt. Nhưng thậm chí nếu nó không có trên hệ thống của bạn, thì bạn vẫn có thể lấy được nó không mất tiền (theo nghĩa “ăn trưa không mất tiền”).
Perl được phân phối theo phép công cộng GNU, nghĩa là thế này, “bạn có thể phân phát chương trình nhị phân Perl chỉ nếu bạn làm ra chương trình gốc có sẵn cho mọi người dùng không phải trả tiền gì cả, và nếu bạn sửa đổi Perl, bạn phải phân phát chương trình gốc của bạn cho nơi sửa đổi của bạn nữa.” Và đó là bản chất của cho không. Bạn có thể lấy chương trình gốc của Perl với giá của một băng trắng hay vài mêga byte qua đường dây. Và không ai có thể khoá Perl và bán cho bạn chỉ mã nhị phân với ý tưởng đặc biệt về “cấu hình phần cứng được hỗ trợ”.
Trong thực tế, nó không chỉ là cho không, nhưng nó chạy còn gọn hơn trên gần như mọi thứ mà có thể gọi là UNIX hay tựa UNIX và có trình biên dịch C. Đấy là vì bộ trình này tới với bản viết cấu hình bí quyết được gọi là Cấu hình, cái sẽ móc và chọc vào các danh mục hệ thống để tìm những thứ nó cần, và điều chỉnh việc đưa vào các tệp và các kí hiệu  được xác định tương ứng, chuyển cho bạn việc kiểm chứng phát hiện của nó.
Bên cạnh các hệ thống UNIX hay tựa UNIX, người đã bị nghiện Perl đem nó sang Amiga, Atari ST, họ Macintosh, VMS, OS/2, thậm chí MS/DOS - và có lẽ còn nhiều hơn nữa vào lúc bạn đọc cuốn sách này. Vị trí chính xác và sự có sẵn của những bản Perl này thì biến động, cho nên bạn phải hỏi quanh (trên nhóm tin Usenet chẳng hạn) để có được thông tin mới nhất. Nếu bạn hoàn toàn không biết gì, thì một bản cũ của Perl đã có trên đĩa phần mềm CD-ROM UNIX Power Tools, của Jerry Peek, Tim OReilly và Mike Loukides (OReilly & Associates/ Random House Co., 1993).

Hỗ trợ
Perl là con đẻ của Larry Wall, và vẫn đang được anh ấy nâng niu. Báo cáo lỗi và yêu cầu nâng cao nói chung đều được sửa chữa trong các lần đưa ra sau, nhưng anh ấy cũng chẳng có nghĩa vụ nào để làm bất kì cái gì với chúng cả. Tuy thế Larry thực sự thích thú nghe từ tất cả chúng ta, và cũng làm việc thực sự để thấy Perl được dùng trên qui mô thế giới.  E-mail trực tiếp cho anh ấy nói chung đều nhận được trả lời (cho dù đấy chỉ đơn thuần là máy trả lời email của anh ấy), và đôi khi là sự đáp ứng con người.
Ích lợi hơn việc viết thư trực tiếp cho Larry là nhóm hỗ trợ Perl trực tuyến toàn thế giới, liên lạc thông qua nhóm tin Usenet comp.lang.perl. Nếu bạn có thể gửi email trên Internet, nhưng chưa vào Usenet, thì bạn có thể tham gia nhóm này bằng cách gửi một yêu cầu tới perl-users-request@virgina.edu, yêu cầu sẽ tới một người có thể nối bạn với cửa khẩu email hai chiều trong nhóm, và cho bạn những hứong dẫn về cách làm việc.
Khi bạn tham gia một nhóm tin, bạn sẽ thấy đại loại có khoảng 30 đến 60 “thư” mỗi ngày (vào lúc bản viết này được soạn thảo) trên đủ mọi chủ đề từ câu hỏi của người mới bắt đầu cho tới vấn đề chuyển chương trình phức tạp và vấn đề giao diện, và thậm chí cả một hay hai chương trình khá lớn.
Nhóm tin gần như được những chuyên gia Perl điều phối. Phần lớn thời gian, câu hỏi của bạn đều có sự trả lời trong vòng vài phút khi bài tin bạn tới tủ nối Usenet chính. Bạn hãy thử mức độ hỗ trợ từ nhà sản xuất phần mềm mình ưa chuộng về việc cho không này! Bản thân Larry cũng đọc về nhóm khi thời gian cho phép, và đôi khi đã xen các bài viết có thẩm quyền vào để chấm dứt việc cãi nhau hay làm sáng tỏ một vấn đề. Sau rốt, không có Usenet, có lẽ không thể có chỗ để dễ dàng công bố Perl cho cả thế giới.
Bên cạnh nhóm tin, bạn cũng nên đọc tạp chí Perl, đi cùng việc phân phối Perl. Một nguồn có thẩm quyền khác là cuốn sách Programming Perl của Larry Wall và Randal L. Schwatrz (OReilly & Associaté, 1990). Programming Perl được xem như “Sách con lừa” vì bìa của nó vẽ con vật này (hệt như cuốn sách này có lẽ sẽ được biết tới với tên sách lạc đà không bướu). Sách con lừa chứa thông tin tham khảo đầy đủ về Perl dưới dạng đóng gọn gàng. Sách con lừa cũng bao gồm một bảng tra tham khảo bật ra tài tình mà chính là nguồn ưa chuộng của cá nhân tôi về thông tin Perl.

Các khái niệm cơ bản
Một bản viết vỏ không gì khác hơn là một dãy các lệnh vỏ nhồi vào trong một tệp văn bản. Tệp này “được làm cho chạy” bằng cách bật một bit thực hiện (qua chmod +x filename) và rồi gõ tên của tệp đó vào lời nhắc của vỏ. Bingo, một chương trình vỏ lớn. Chẳng hạn, một bản viết để chạy chỉ lệnh date theo sau bởi chỉ lệnh who  có thể được tạo ra và thực hiện như thế này:
$ echo date > somecript
$ echo who > somecript
$ cat somescript
date
who
$ chmod _x somescript
$ somescript
[output of date followed by who]
$
Tương tự như thế, một chương trình Perl là một bó các câu lệnh và định nghĩa Perl được ném vào trong một tệp. Rồi bạn bật bit thực hiện và gõ tên của tệp này tại lời nhắc của vỏ. Tuy nhiên, tệp này phải chỉ ra rằng đây là một chương trình Perl và không phải là chương trình vỏ, nên chúng ta cần một bước phụ.
#! /usr/bin/perl
làm dòng đầu tiên của tệp này. Nhưng nếu Perl của bạn bị kẹt vào một nơi không chuẩn, hay hệ điều hành tựa UNIX của bạn không hiểu dòng #!, thì bạn có thêm việc phải làm. Hãy hỏi người cài đặt Perl về điều này. Các thí dụ trong sách này giả sử rằng bạn dùng cơ chế thông thường này.
Perl là một ngôn ngữ phi định dạng kiểu như C - khoảng trắng giữa các hiệu bài (những phần tử của chương trình, như print hay +) là tuỳ chọn, trừ phi hai hiệu bài đi với nhau có thể bị lầm lẫn thành một hiệu bài khác, trong trường hợp đó thì khoảng trắng thuộc loại nào đó là bắt buộc. (Khoảng trắng bao gồm dấu cách, dấu tab, dòng mới, về đầu dòng hay kéo giấy.) Có một vài cấu trúc đòi hỏi một loại khoảng trắng nào đó ở chỗ nào đó, nhưng chúng sẽ được trỏ ra khi ta nói tới chúng. Bạn có thể giả thiết rằng loại và khối lượng khoảng trắng giữa các hiệu bài là tuỳ ý trong các trường hợp khác.
Mặc dầu gần như tất cả các chương trình Perl đều có thể được viết tất cả trên một dòng, một cách điển hình chương trình Perl cũng hay được viết tụt lề như chương trình C, với những phần câu lệnh lồng nhau được viết tụt vào hơn so với phần bao quanh. Bạn sẽ thấy đầy những thí dụ chỉ ra phong cách viết tụt lề điển hình trong toàn bộ cuốn sách này.
Cũng giống như bản viết về vỏ, chương trình Perl bao gồm tất cả các câu lệnh perl về tệp được lấy tổ hợp chung như mọt trình lớn cần thực hiện. Không có khái niệm về trình “chính” main như trong C.
Chú thích của Perl giống như chú thích của lớp vỏ (hiện đại). Bất kì cái gì nằm giữa một dấu thăng (#) tới cuối dòng đều là một chú thích. Không có khái niệm về chú thích trên nhiều dòng như C.
Không giống hầu hết các lớp vỏ (nhưng giống như awk và sed), bộ thông dịch Perl phân tích và biên dịch hoàn toàn chương trình trước khi thực hiện nó. Điều này có nghĩa là bạn không bao giờ nhận được lỗi cú pháp từ chương trình một khi chương trình đã bắt đầu chạy, và cũng có nghĩa là khoảng trắng và chú thích biến mất và sẽ không làm chậm chương trình. Trong thực tế, giai đoạn biên dịch này bảo đảm việc thực hiện nhanh chóng của các thao tác Perl một khi nó được bắt đầu, và nó cung cấp động cơ phụ để loại bỏ C như một ngôn ngữ tiện ích hệ thống đơn thuần dựa trên nền tảng là C được biên dịch.
Việc biên dịch này không mất thời gian - sẽ là phi hiệu quả nếu một chương trình Perl cực lớn lại chỉ thực hiện một nhiệm vụ nhỏ bé chóng vánh (trong số nhiều nhiệm vụ tiềm năng) và rồi ra, vì thời gian chạy cho chương trình sẽ nhỏ xíu nếu so với thời gian dịch.
Cho nên Perl giống như một bộ biên dịch và thông dịch. Nó là biên dịch vì chương trình được đọc và phân tích hoàn toàn trước khi câu lệnh đầu tiên được thực hiện. Nó là bộ thông dịch vì không có mã đích ngồi đâu đó trút đầy không gian đĩa. Theo một cách nào đó, nó là tốt nhất cho cả hai loại này. Phải thú thực, việc ẩn đi mã đích đã dịch giữa những lời gọi thì hay, và đó là trong danh sách mong ước cho Perl tương lai của Larry.

_________________
..................................................................................
nhocyeu_ufa
..................................................................................

Hình ảnhHình ảnh


album1 - hình chụp với Ubuntu
album2 - ảnh cá nhân & bên ngoài


Sửa lần cuối bởi nhocyeu_ufa vào ngày T.Năm Tháng 11 22, 2007 9:15 am với 1 lần sửa.

Đầu trang
 Xem thông tin cá nhân  
 
Gửi bàiĐã gửi: T.Năm Tháng 11 22, 2007 9:32 am 
Đóng góp tích cực
Hình đại diện của thành viên

Ngày tham gia: T.Tư Tháng 11 21, 2007 1:22 pm
Bài viết: 264
Đến từ: Viet Nam
Nhocyeu_ufa lượm lặt gần xa

Dạo qua Perl
Chúng ta bắt đầu cuộc hành trình của mình qua Perl bằng việc đi dạo một chút. Việc đi dạo này sẽ giới thiệu một số các tính năng khác nhau bằng cách bổ sung vào một ứng dụng nhỏ. Giải thích ở đây là cực kì ngắn gọn - mỗi vùng chủ đề đều được thảo luận chi tiết hơn rất nhiều về sau trong cuốn sách này. Nhưng cuộc đi dạo nhỏ này sẽ cho bạn kinh nghiệm nhanh chóng về ngôn ngữ, và bạn có thể quyết định liệu bạn có thực sự muốn kết thúc cuốn sách này hay đọc thêm các tin Usenet hay chạy đi chơi trượt tuyết.
Chương trình “Xin chào mọi người”
Ta hãy nhìn vào một chương trình nhỏ mà thực tế có làm điều gì đó. Đây là chương trình “Xin chào mọi người”:
#!/usr/bin/perl
print “Xin chào mọi người\n”;
Dòng đầu tiên là câu thần chú nói rằng đây là chương trình Perl. Nó cũng là lời chú thích cho Perl - hãy nhớ rằng lời chú thích là bất kì cái gì nằm sau dấu thăng cho tới cuối dòng, giống như hầu hết các lớp vỏ hiện đại hay awk.
Dòng thứ hai là toàn bộ phần thực hiện được của chương trình này. Tại đây chúng ta thấy câu lệnh print. Từ khoá print bắt đầu chương trình, và nó có một đối, một xâu văn bản kiểu C. Bên trong xâu này, tổ hợp kí tự \n biểu thị cho kí tự dòng mới; hệt như trong C. Câu lệnh print được kết thúc bởi dấu chấm phẩy (;). Giống như C, tất cả các câu lệnh đơn giản đều kết thúc bằng chấm phẩy** Dấu chấm phẩy có thể bỏ đi khi câu lệnh này là câu lệnh cuối của một khối hay tệp hay eval. .
Khi bạn gọi chương trình này, phần lõi sẽ gọi bộ thông dịch Perl, phân tích câu toàn bộ chương trình (hai dòng, kể cả dòng chú thích đầu tiên) và rồi thực hiện dạng đã dịch. Thao tác đầu tiên và duy nhất là thực hiện toán tử print, điều này gửi đối của nó ra lối ra. Sau khi chương trình đã hoàn tất, thì tiến trình Perl ra, cho lại một mã ra thành công cho lớp vỏ.
Hỏi câu hỏi và nhớ kết quả
Ta hãy thêm một chút phức tạp hơn. Từ Xin chào mọi người là một sự đụng chạm lạnh nhạt và cứng rắn. Ta hãy làm cho chương trình gọi bạn theo tên bạn. Để làm việc này, ta cần một chỗ giữ tên, một cách hỏi tên, và một cách nhận câu trả lời.
Một loại đặt chỗ giữ giá trị (tựa như một tên) là biến vô hướng. Với chương trình này, ta sẽ dùng biến vô hướng $name để giữ tên bạn. Chúng ta sẽ đi chi tiết hơn trong Chương 2, Dữ liệu vô hướng, về những gì mà biến này có thể giữ, và những gì bạn có thể làm với chúng. Hiện tại, giả sử rằng bạn có thể giữ một số hay xâu (dãy các kí tự) trong biến vô hướng.
Chương trình này cần hỏi về tên. Để làm điều đó, ta cần một cách nhắc và một cách nhận cái vào. Chương trình trước đã chỉ ra cho ta cách nhắc - dùng toán tử print. Và cách để nhận một dòng từ thiết bị cuối là với toán tử , mà (như ta sẽ dùng nó ở đây) lấy một dòng cái vào. Ta gán cái vào này cho biến $name. Điều này cho ta chương trình:
print “Tên bạn là gì? : ”;
$name = ;
Giá trị của $name tại điểm này có một dấu dòng mới kết thúc (Randal có trong Randal\n). Để vứt bỏ điều đó, chúng ta dùng toán tử chop(), toán tử lấy một biến vô hướng làm đối duy nhất và bỏ đi kí tự cuối từ giá trị xâu của biến:
chop($name);
Bây giờ tất cả những gì ta cần làm là nói Xin chào, tiếp đó là giá trị của biến $name, mà ta có thể thực hiện theo kiểu vỏ bằng cách nhúng biến này vào bên trong xâu có ngoặc kép:
print “Xin chào, $name!\n”;
Giống như lớp vỏ, nếu ta muốn một dấu đô la thay vì tham khảo biến vô hướng, thì ta có thể đặt trước dấu đô la với một dấu sổ chéo ngược.
Gắn tất cả lại, ta được:
#!/usr/bin/perl
print “Tên bạn là gì? ”;
$name = ;
chop($name);
print “Xin chào, $name!\n”;
Bổ sung chọn lựa
Bây giờ ta muốn có một lời chào đặc biệt cho Randal, nhưng muốn lời chào thông thường cho mọi người khác. Để làm điều này, ta cần so sánh tên đã được đưa vào với xâu Randal, và nếu hai xâu là một, thì làm điều gì đó đặc biệt. Ta hãy bổ sung thêm lệnh rẽ nhánh if-then-else và phép so sánh vào chương trình:
#!/usr/bin/perl
print “Tên bạn là gì? ”;
$name = ;
chop($name);
if ($name eq “Randal”)  {
print “Xin chào Randal! Tốt quá anh lại ở đây!\n”;
} else {
     print “Xin chào, $name!\n”; # chào mừng thông thường
}
Toán tử eq so sánh hai xâu. Nếu chúng bằng nhau (từng kí tự một, và có cùng chiều dài), thì kết quả là đúng. (Không có toán tử này trong C, và awk phải dùng cùng toán tử cho xâu và số và tạo ra việc đoán có rèn luyện.)
Câu lệnh if chọn xem khối câu lệnh nào (giữa các dấu ngoặc nhọn sánh đúng) là được thực hiện - nếu biểu thức là đúng, đó là khối thứ nhất, nếu không thì đó là khối thứ hai.
Đoán từ bí mật
Nào, vì chúng ta đã có một tên nên ta hãy để cho một người chạy chương trình đoán một từ bí mật. Với mọi người ngoại trừ Randal, chúng ta sẽ để cho chương trình cứ hỏi lặp lại để đoán cho đến khi nào người này đoán được đúng. Trước hết ta hãy xem chương trình này và rồi xem giải thích:
#! /usr/bin/perl
$secretword = “llama”; # từ bí mật
print “Tên bạn là gì?” ;
$name = ;
chop($name);
if ($name eq “Randal”) {
print “Xin chào, Randal! May quá anh ở đây!\n”;
} else {
print “Xin chào, $name!\n”;  # chào thông thường
print “Từ bí mật là gì?” ;
$guess = ;
chop($guess);
while ($guess ne $secrectword)  {
  print “Sai rồi, thử lại đi. Từ bí mật là gì?”;
  $guess = ;
  chop($guess);
}
}
Trước hết, ta định nghĩa từ bí mật bằng việc đặt nó vào trong biến vô hướng khác, $secretword. Sau khi đón chào, một người (không phải Randal) sẽ được yêu cầu (với một câu lệnh print khác) đoán chữ. Lời đoán rồi được đem ra so sánh với từ bí mật bằng việc dùng toán tử ne, mà sẽ cho lại đúng nếu các xâu này không bằng nhau (đây là toán tử logic ngược với toán tử eq). Kết quả của việc so sánh sẽ kiểm soát cho trình while, chu trình này thực hiện khối thân cho tới khi việc so sánh vẫn còn đúng.
Tất nhiên, chương trình này không phải là an toàn lắm, vì bất kì ai mệt với việc đoán cũng đều có thể đơn thuần ngắt chương trình và quay trở về lời nhắc, hay thậm chí còn nhìn qua chương trình gốc để xác định ra từ. Nhưng, chúng ta hiện tại chưa định viết một hệ thống an toàn, chỉ xem như một thí dụ cho trang hiện tại của cuốn sách này.
Nhiều từ bí mật
Ta hãy xem cách thức mình có thể sửa đổi đoạn chương trình này để cho phép có nhiều từ bí mật. Bằng việc dùng điều ta đã thấy, chúng ta có thể so sánh lời đoán lặp đi lặp lại theo một chuỗi câu trả lời rõ được cất giữ trong các biến vô hướng tách biệt. Tuy nhiên, một danh sách như vậy sẽ khó mà thay đổi hay đọc vào từ một tệp hay máy tính trên cơ sở ngày làm việc thường lệ.
Một giải pháp tốt hơn là cất giữ tất cả các câu trả lời có thể vào trong một cấu trúc dữ liệu gọi là danh sách hay mảng. Mỗi phần tử của mảng đều là một biến vô hướng tách biệt mà có thể được đặt giá trị hay thâm nhập độc lập. Toàn bộ mảng cũng có thể được trao cho một giá trị trong một cú đột nhập. Ta có thể gán một giá trị cho toàn bộ mảng có tên @words sao cho nó chứa ba mật hiệu tốt có thể có:
@words = (“camel”, “llama”, “oyster”);
Tên biến mảng bắt đầu với @, cho nên chúng là khác biệt với các tên biến vô hướng.
Một khi mảng đã được gán thì ta có thể thâm nhập vào từng phần tử bằng việc dùng một tham khảo chỉ số. Cho nên $words[0] là camel, $words[1] là llama, $words[2] là oyster. Chỉ cố cũng có thể là một biểu thức, cho nên nếu ta đặt $i là 2 thì $words[$i] là oyster. (Tham khảo chỉ số bắt đầu với $ thay vì @ vì chúng tham khảo tới một phần tử riêng của mảng thay vì toàn bộ mảng.) Quay trở lại với thí dụ trước đây của ta:
#! /usr/bin/perl
$words = (“camel”, “llama”, “oyster”); # từ bí mật
print “Tên bạn là gì?” ;
$name = ;
chop($name);
if ($name eq “Randal”) {
print “Xin chào, Randal! May quá anh ở đây!\n”;
} else {
print “Xin chào, $name!\n”;  # chào thông thường
print “Từ bí mật là gì?” ;
$guess = ;
chop($guess);
$i = 0;  # thử từ này trước hết
$correct = “ có thể”;  # từ đoán có đúng hay không?
while ($correct eq $guess)  {  # cứ kiểm tra đến khi biết
       if ($words[$i] eq $guess)  {  #  đúng không
  $correct = “có”;  #  có
       }  elsif  ($i < 2)  {  # cần phải xét thêm từ nữa?
  $i = $i + 1;  #  nhìn vào từ tiếp lần sau
       }  else  #  hết rồi, thế là hỏng
  print “Sai rồi, thử lại đi. Từ bí mật là gì?”;
  $guess = ;
  chop($guess);
  $i = 0;  # bắt đầu kiểm tra từ đầu lần nữa
       }
}  # kết thúc của while not correct
}   #  kết thúc của “not Randal”
Bạn sẽ để ý rằng chúng ta đang dùng biến vô hướng $correct để chỉ ra rằng chúng ta vẫn đang tìm ra mật hiệu đúng, hay rằng chúng ta không tìm thấy.
Chương trình này cũng chỉ ra khối elsif của câu lệnh if-then-else. Không có lệnh nào tương đương như thế trong C hay awk - đó là việc viết tắt của khối else cùng với một điều kiện if mới, nhưng không lồng bên trong cặp dấu ngoặc nhọn khác. Đây chính là cái rất giống Perl để so sánh một tập các điều kiện trong một dây chuyền phân tầng if-elsif-elsif-elsif-else.
Cho mỗi người một từ bí mật khác nhau
Trong chương trình trước, bất kì người nào tới cũng đều có thể đoán bất kì từ nào trong ba từ này và có thể thành công. Nếu ta muốn từ bí mật là khác nhau cho mỗi người, thì ta cần một bảng sánh giữa người và từ:

Người Từ bí mật
Fred
Barney
Betty
Wilma Camel
Llama
Oyster
Oyster

Chú ý rằng cả Betty và Wilma đều có cùng từ bí mật. Điều này là được.
Cách dễ nhất để cất giữ một bảng như thế trong Perl là bằng một mảng kết hợp. Mỗi phần tử của mảng này giữ một giá trị vô hướng tách biệt (hệt như kiểu mảng khác), nhưng các mảng lại được tham khảo tới theo khoá, mà có thể là bất kì giá trị vô hướng nào (bất kì xâu hay số, kể cả số không nguyên và giá trị âm). Để tạo ra một mảng kết hợp được gọi là %words (chú ý % chứ không phải là @) với khoá và giá trị được cho trong bảng trên, ta gán một giá trị cho %words (như ta đã làm nhiều trước đây với mảng khác):
%words = (“fred”, “camel”, “barney”, “llama”,
  “betty”, “oyster”, “wilma”, “oyster”) ;
Mỗi cặp giá trị trong danh sách đều biểu thị cho một khoá và giá trị tương ứng của nó trong mảng kết hợp. Chú ý rằng ta đã bẻ phép gán này ra hai dòng mà không có bất kì loại kí tự nối dòng nào, vì khoảng trắng nói chung là vô nghĩa trong chương trình Perl.
Để tìm ra từ bí mật cho Betty, ta cần dùng Betty như khoá trong một tham khảo vào mảng kết hợp %words, qua một biểu thức nào đó như %words{“betty”}. Giá trị của tham khảo này là oyster, tương tự như điều ta đã làm trước đây với mảng khác. Cũng như trước đây, khoá có thể là bất kì biểu thức nào, cho nên đặt $person với betty và tính $words{$person} cũng cho oyster.
Gắn tất cả những điều này lại ta được chương trình như thế này:
#! /usr/bin/perl
%words = (“fred”, “camel”, “barney”, “llama”,
  “betty”, “oyster”, “wilma”, “oyster”) ;
print “Tên bạn là gì?” ;
$name = ;
chop($name);
if ($name eq “Randal”) {
print “Xin chào, Randal! May quá anh ở đây!\n”;
} else {
print “Xin chào, $name!\n”;  # chào thông thường
$secretword = $words{$name};  #  lấy từ bí mật
print “Từ bí mật là gì?” ;
$guess = ;
chop($guess);
while ($correct ne $secretwords)  { 
  print “Sai rồi, thử lại đi. Từ bí mật là gì?”;
  $guess = ;
  chop($guess);
}  # kết thúc của while
}   #  kết thúc của “not Randal”
Bạn hãy chú ý nhìn vào từ bí mật. Nếu không tìm thấy từ này thì giá trị của $secretword sẽ là một xâu rỗng** Được, đấy chính là giá trị undef, nhưng nó trông như một xâu rỗng cho toán tử eq, mà ta có thể kiểm tra liệu ta có muốn xác định một từ bí mật mặc định cho ai đó khác không. Đây là cách xem nó:
[... phần còn lại của chương trình đã bị xoá...]
$secretword = $words{$name};  #  lấy từ bí mật
if  ($secretword eq “”)  {  # ấy, không thấy
$secretword = “đồ cáu kỉnh”;  # chắc chắn, sao không là vịt?
}
print “Từ bí mật là gì?” ;
[... phần còn lại của chương trình đã bị xoá...]
Giải quyết định dạng cái vào thay đổi
Nếu tôi đưa vào Randal L. Schwartz hay randal thay vì Randal thì tôi sẽ bị đóng cục lại với phần người dùng còn lại, vì việc so sánh eq thì lại so sánh đúng sự bằng nhau. Ta hãy xem một cách giải quyết cho điều đó.
Giả sử tôi muốn tìm bất kì xâu nào bắt đầu với Randal, thay vì chỉ là một xâu bằng Randal. Tôi có thể làm điều này trong sed hay awk hoặc grep với một biểu thức chính qui: một tiêu bản sẽ xác định ra một tập hợp các xâu sánh đúng. Giống như trong sed  hay grep, biểu thức chính qui trong Perl để sánh bất kì xâu nào bắt đầu với Randal là ^Randal. Để sánh xâu này với xâu trong $name, chúng ta dùng toán tử sánh như sau:
if  ($name =~ /^Randal/)  {
## có, sánh đúng
}  else  {
## không, sánh sai
}
Chú ý rằng biểu thức chính qui được định biên bởi dấu sổ chéo. Bên trong các dấu sổ chéo, dấu cách và khoảng trắng là có nghĩa, hệt như chúng ở bên trong xâu.
Điều này gần như thế, nhưng nó lại không giải quyết việc lựa ra randal hay loại bỏ Randall. Để chấp nhận randal, chúng ta thêm tuỳ chọn bỏ qua hoa thường, một chữ i nhỏ được thêm vào sau dấu sổ chéo đóng. Để loại bỏ Randall, ta thêm một đánh dấu đặc biệt định biên từ (tương tự với vi  và một số bản của grep) dưới dạng của \b trong biểu thức chính qui. Điều này đảm bảo rằng kí tự đi sau l đầu tiên trong biểu thức chính qui không phải là một kí tự khác. Điều này làm thay đổi biểu thức chính qui thành /^randal\b/i, mà có nghĩa là “randal tại đầu xâu, không có kí tự hay chữ số nào theo sau, và chấp nhận cả hai kiểu chữ hoa thường.”

_________________
..................................................................................
nhocyeu_ufa
..................................................................................

Hình ảnhHình ảnh


album1 - hình chụp với Ubuntu
album2 - ảnh cá nhân & bên ngoài


Sửa lần cuối bởi nhocyeu_ufa vào ngày T.Năm Tháng 11 22, 2007 9:45 am với 1 lần sửa.

Đầu trang
 Xem thông tin cá nhân  
 
Gửi bàiĐã gửi: T.Năm Tháng 11 22, 2007 9:33 am 
Đóng góp tích cực
Hình đại diện của thành viên

Ngày tham gia: T.Tư Tháng 11 21, 2007 1:22 pm
Bài viết: 264
Đến từ: Viet Nam
Nhocyeu_ufa lượm lặt gần xa

Khi gắn tất cả lại với phần còn lại của chương trình thì nó sẽ giống như thế này:
#! /usr/bin/perl
%words = (“fred”, “camel”, “barney”, “llama”,
  “betty”, “oyster”, “wilma”, “oyster”) ;
print “Tên bạn là gì?” ;
$name = ;
chop($name);
if ($name =~ /^randal\b/i ) {
print “Xin chào, Randal! May quá anh ở đây!\n”;
} else {
print “Xin chào, $name!\n”;  # chào thông thường
$secretword = $words{$name};  #  lấy từ bí mật
if  ($secretword eq “”)  {  # ấy, không thấy
    $secretword = “đồ cáu kỉnh”;  # chắc chắn, sao không là vịt?
}
print “Từ bí mật là gì?” ;
$guess = ;
chop($guess);
while ($correct ne $secretwords)  { 
  print “Sai rồi, thử lại đi. Từ bí mật là gì?”;
  $guess = ;
  chop($guess);
}  # kết thúc của while
}   #  kết thúc của “not Randal”
Như bạn có thể thấy, chương trình này khác xa với chương trình đơn giản Xin chào, mọi người, nhưng nó vẫn còn rất nhỏ bé và làm việc được, và nó quả làm được tí chút với cái ngắn xíu vậy. đây chính là cách thức của Perl.
Perl đưa ra tính năng về các biểu thức chính qui có trong mọi trình tiện ích UNIX chuẩn (và thậm chí trong một số không chuẩn). Không chỉ có thế, nhưng cách thức Perl giải quyết cho việc đối sánh xâu là cách nhanh nhất trên hành tin này, cho nên bạn không bị mất hiệu năng. (Một chương trình giống như grep được viết trong Perl thường đánh bại chương trình grep được các nhà cung cấp viết trong C với hầu hết các cái vào. Điều này có nghĩa là thậm chí grep không thực hiện một việc của nó thật tốt.)
Làm cho công bằng với mọi người
Vậy bây giờ tôi có thể đưa vào Randal hay randal hay Randal L. Schwartz, nhưng với những người khác thì sao? Barney vẫn phải nói đúng barney (thậm chí không được có barney với một dấu cách theo sau).
Để công bằng cho Barey, chúng ta cần nắm được từ đầu của bất kì cái gì được đưa vào, và rồi chuyển nó thành chữ thường trước khi ta tra tên trong bảng. Ta làm điều này bằng hai toán tử: toán tử substitute, tìm ra một biểu thức chính qui và thay thế nó bằng một xâu, và toán tử translate, để đặt xâu này thành chữ thường.
Trước hết, toán tử thay thế: chúng ta muốn lấy nội dung của $name, tìm kí tự đầu tiên không là từ, và loại đi mọi thứ từ đây cho đến cuối xâu. /\W.*/ là một biểu thức chính qui mà ta đang tìm kiếm - \W viết tắt cho kí tự không phải là từ (một cái gì đó không phải là chữ, chữ số hay gạch thấp) và .* có nghĩa là bất kì kí tự nào từ đấy tới cuối dòng. Bây giờ, để loại những kí tự này đi, ta cần lấy bất kì bộ phận nào của xâu sánh đúng với biểu thức chính qui này và thay nó với cái không có gì:
$name =~ s/\W.*//;
Chúng ta đang dùng cùng toán tử =~ mà ta đã dùng trước đó, nhưng bây giờ bên vế phải ta có toán tử thay thế: chữ s được theo sau bởi một biểu thức chính qui và xâu được định biên bởi dấu sổ chéo. (Xâu trong thí dụ này là xâu rỗng giữa dấu sổ chéo thứ hai và thứ ba.) Toán tử này trông giống và hành động rất giống như phép thay thế của các trình soạn thảo khác nhau.
Bây giờ để có được bất kì cái gì còn lại trở thành chữ thường thì ta phải dịch xâu này dùng toán tử tr. Nó trông rất giống chỉ lệnh tr của UNIX, nhận một danh sách các kí tự để tìm và một danh sách các kí tự để thay thế chúng. Với thí dụ của ta, để đặt nội dung của $name thành chữ thường, ta dùng:
$name =~ tr/A-Z/a-z/;
Các dấu sổ chéo phân tách các danh sách kí tự cần tìm và cần thay thế. Dấu gạch ngang giữa A và Z thay thế cho tất cả các kí tự nằm giữa, cho nên chúng ta có hai danh sách, mỗi danh sách có 26 kí tự. Khi toán tử tr tìm thấy một kí tự từ một xâu trong danh sách thứ nhất thì kí tự đó sẽ được thay thế bằng kí tự tương ứng trong danh sách thứ hai. Cho nên tất cả các chữ hoa A trở thành chữ thường a, và cứ như thế** Các chuyên gia sẽ lưu ý rằng tôi cũng đã xây dựng một cái gì đó tựa như s/(\S*).*/\L$1/ để làm tất cả điều này trong một cú đột kích, nhưng các chuyên gia có lẽ sẽ không đọc mục này. .
Gắn tất cả lại với mọi thứ khác sẽ cho kết quả trong:
#! /usr/bin/perl
%words = (“fred”, “camel”, “barney”, “llama”,
  “betty”, “oyster”, “wilma”, “oyster”) ;
print “Tên bạn là gì?” ;
$name = ;
chop($name);
$original_name = $name;  #  cất giữ để chào mừng
$name =~ s/\W.*//;  #  bỏ mọi thứ sau từ đầu
$name =~ tr/A-Z/a-z/;  #  mọi thứ thành chữ thường
if ($name eq “randal” ) {
print “Xin chào, Randal! May quá anh ở đây!\n”;
} else {
print “Xin chào, $original_name!\n”;  # chào thông thường
$secretword = $words{$name};  #  lấy từ bí mật
if  ($secretword eq “”)  {  # ấy, không thấy
    $secretword = “đồ cáu kỉnh”;  # chắc chắn, sao không là vịt?
}
print “Từ bí mật là gì?” ;
$guess = ;
chop($guess);
while ($correct ne $secretwords)  { 
  print “Sai rồi, thử lại đi. Từ bí mật là gì?”;
  $guess = ;
  chop($guess);
}  # kết thúc của while
}   #  kết thúc của “not Randal”
Bạn hãy để ý đến cách thức biểu thức chính qui sánh đúng với tên tôi Randal đã lại trở thành việc so sánh đơn giản. Sau rốt, cả Randal L. Schwartz và Randal đều trở thành randal sau khi việc thay thế và dịch. Và mọi người khác cũng có được sự công bằng, vì Fred và Fred Flinstone cả hai đều trở thành fred, Barney Rubble và Barney, the little guy sẽ trở thành barney, vân vân.
Với chỉ vài câu lệnh, chúng ta đã tạo ra một chương trình thân thiện người dùng hơn nhiều. Bạn sẽ thấy rằng việc diễn tả thao tác xâu phức tạp với vài nét là một trong nhiều điểm mạnh của Perl.
Tuy nhiên, chém vào tên để cho ta có thể so sánh nó và tra cứu nó trong bảng thì sẽ phá huỷ mất tên ta vừa đưa vào. Cho nên, trước khi chém vào tên, cần phải cất giữ nó vào trong @original_name. (Giống như các kí hiệu C, biến Perl bao gồm các chữ, chữ số và dấu gạch thấp và có thể có chiều dài gần như không giới hạn.) Vậy ta có thể làm tham khảo tới $original_name về sau.
Perl có nhiều cách để giám sát và chặt cắt xâu. bạn sẽ thấy phần lớn chúng trong Chương 7, Biểu thức chính qui và Chương 15, Việc chuyển đổi dữ liệu khác.
Làm cho nó mô đun hơn một chút
Bởi vì chúng ta đã thêm quá nhiều mã nên ta phải duyệt qua nhiều dòng chi tiết trước khi ta có thể thu được toàn bộ luồng chương trình. Điều ta cần là tách bạch logic mức cao (hỏi tên, chu trình dựa trên từ bí mật đưa vào) với các chi tiết (so sánh một từ bí mật với từ đã biết). Chúng ta có thể làm điều này cho rõ ràng, hoặc có thể bởi vì một người đang viết phần cao cấp còn người khác thì viết (hay đã viết) phần chi tiết.
Perl cung cấp các chương trình con có tham biến và giá trị cho lại. Một chương trình con được xác định một khi nào đó trong chương trình, và rồi có thể được dùng lặp đi lặp lại bằng việc gọi từ bên trong bất kì biểu thức nào.
Với chương trình nhỏ nhưng tăng trưởng nhanh của chúng ta, ta hãy tạo ra một chương trình con tên là &good_word (tất cả các tên chương trình con đều bắt đầu với một dấu và &) mà nhận một tên đã sạch và một từ đoán, rồi cho lại true nếu từ đó là đúng, và cho lại false nếu không đúng. Việc xác định chương trình con đó tựa như thế này:
sub good_word  {
local($somename, $someguess) = @_; #  tên tham biến
$somename =~ s/\W.*//;  #  bỏ mọi thứ sau từ đầu
$somename =~ tr/A-Z/a-z/;  #  mọi thứ thành chữ thường
if  ($somename eq “randal”)  {  #  không nên đoán
  1;  #giá trị cho lại là true
} elsif (($words{$somename} || “đồ cáu kỉnh”) eq $someguess)  {
  1;  #  giá trị cho lại là true
}  else  {
  0;  #  cho lại giá trị false
}
}
Trước hết, việc định nghĩa ra một chương trình con bao gồm một từ dành riêng sub đi theo sau là tên chương trình con (không có dấu và &)  tiếp nữa là một khối mã lệnh (được định biên bởi dấu ngoặc nhọn). Định nghĩa này có thể để vào bất kì đâu trong tệp chương trình, nhưng phần lớn mọi người thích để chúng vào cuối.
Dòng đầu tiên trong định nghĩa đặc biệt này là một phép gán làm việc sao các giá trị của hai tham biến của chương trình này vào hai biến cục bộ có tên $somename và $someguess. (local() xác định hai biến là cục bộ cho chương trình con này, và các tham biến ban đầu trong một mảng cục bộ đặc biệt gọi là @_.)
Hai dòng tiếp làm sạch tên, cũng giống như bản trước của chương trình.
Câu lệnh if-elsif-else quyết định xem từ được đoán ($someguess) là có đúng cho tên ($somename) hay không. Randal không nên làm nó thành chương trình con này, nhưng ngay cả nếu nó có, thì dù từ nào được đoán cũng đều OK cả.
Biểu thức cuối cùng được tính trong chương trình con là cho lại giá trị. Chúng ta sẽ thấy cách cho lại giá trị được dùng sau khi tôi kết thúc việc mô tả định nghĩa về chương trình con.
Phép kiểm tra cho phần elsif trông có phức tạp hơn một chút - ta hãy chia nó ra:
($words{$somename} ||  “đồ cáu kỉnh”)  eq  $someguess
Vật thứ nhất bên trong dấu ngoặc là mảng kết hợp quen thuộc của ta, cho một giá trị nào đó từ %words dựa trên khoá $somename. Toán tử đứng giữa giá trị đó và xâu đồ cáu kỉnh là toán tử || (phép hoặc logic) như được dùng trong C và awk và các vỏ khác. Nếu việc tra cứu từ mảng kết hợp có một giá trị (nghĩa là khoá $somename là trong mảng), thì giá trị của biểu thức là giá trị đó. Nếu khoá không tìm được, thì xâu đồ cáu kỉnh sẽ được dùng thay. Đây chính là một vật kiểu Perl thường làm - xác định một biểu thức nào đó, và rồi đưa ra một giá trị mặc định bằng cách dùng || nếu biểu thức này có thể trở thành sai.
Trong mọi trường hợp, dù đó là một giá trị từ mảng kết hợp, hay giá trị mặc định đồ cáu kỉnh, chúng ta đều so sánh nó với bất kì cái gì được đoán. Nếu việc so sánh là đúng thì ta cho lại 1, nếu không ta cho lại 0.
Bây giờ ta hãy tích hợp tất cả những điều này với phần còn lại của chương trình:
#! /usr/bin/perl
%words = (“fred”, “camel”, “barney”, “llama”,
  “betty”, “oyster”, “wilma”, “oyster”) ;
print “Tên bạn là gì?” ;
$name = ;
chop($name);
if ($name =~ /^randal\b/i ) {  #  trở lại cách khác
print “Xin chào, Randal! May quá anh ở đây!\n”;
} else {
print “Xin chào, $original_name!\n”;  # chào thông thường
print “Từ bí mật là gì?” ;
$guess = ;
chop($guess);
while ( ! &good_word($name, $guess))  { 
  print “Sai rồi, thử lại đi. Từ bí mật là gì?”;
  $guess = ;
  chop($guess);
}
}
[ ... thêm vào định nghĩa của &good_word ở đây ...]
Chú ý rằng chúng ta đã quay trở lại với biểu thức chính qui để kiểm tra Randal, vì bây giờ không cần kéo một phần tên thứ nhất và chuyển nó thành chữ thường, chừng nào còn liên quan tới chương trình chính.
Sự khác biệt lớn là chu trình while có chứa &good_word. Tại đây, chúng ta thấy một lời gọi tới chương trình con, truyền cho nó hai đối, $name và $guess. Bên trong chương trình con này, giá trị của $somename được đặt từ tham biến thứ nhất, trong trường hợp này là $name. Giống thế, $someguess được đặt từ tham biến thứ hai, $guess.
Giá trị do chương trình con cho lại (hoặc 1 hoặc 0, nhớ lại định nghĩa đã nêu trước đây) là âm với toán tử tiền tố ! (phép phủ định logic). Như trong C, toán tử này cho lại đúng nếu biểu thức đi sau là sai, và ngược lại. Kết quả của phép phủ định này sẽ kiểm soát chu trình while. Bạn có thể đọc điều này là “trong khi không phải là từ đúng...”. Nhiều chương trình Perl viết tốt đọc rất giống tiếng Anh, đưa lại cho bạn một chút tự do với Perl hay tiếng Anh. (Nhưng bạn chắc chắn không đoạt giải Pulitzer theo cách đó.)
Chú ý rằng chương trình con này giả thiết rằng giá trị của mảng %words được chương trình chính đặt. Điều này không đặc biệt là hay, nhưng chẳng có gì so sánh được với static của C đối với chương trình con - nói chung, tất cả các biến nếu không nói khác đi mà được tạo ra với toán tử local() thì đều là toàn cục đối với toàn bộ chương trình. Trong thực tế, đây chỉ là vấn đề nhỏ, và người ta thì có được tính sáng tạo về cách đặt tên biến dài hạn.

Chuyển danh sách từ bí mật vào tệp riêng biệt
Giả sử ta muốn dùng chung danh sách từ bí mật cho ba chương trình. Nếu ta cất giữ danh sách từ như ta đã làm thì ta sẽ cần phải thay đổi tất cả ba chương trình này khi Betty quyết định rằng từ bí mật của cô sẽ là swine thay vì oyster. Điều này có thể thành phiền phức, đặc biệt khi xem xét tới việc Betty lại thường xuyên thích thay đổi ý định.
Cho nên, ta hãy đặt danh sách từ vào một tệp, và rồi đọc tệp này để thu được danh sách từ vào trong chương trình. Để làm điều này, ta cần tạo ra một kênh vào/ra được gọi là tước hiệu tệp. Chương trình Perl của bạn sẽ tự động lấy ba tước hiệu tệp gọi là STDIN, STDOUT và STDERR, tương ứng với ba kênh vào ra chuẩn cho chương trình UNIX. Chúng ta cũng đã dùng tước hiệu STDIN để đọc dữ liệu từ người chạy chương trình. Bây giờ, đấy chỉ là việc lấy một tước hiệu khác để gắn với một tệp do ta tạo ra.
Sau đây là một đoạn mã nhỏ để làm điều đó:
sub init_words  {
open (WORDSLIST, “wordslist”);
while ($name = )  {
  chop ($name);
  $word = ;
  chop($word);
  $words{$name} = $word;
}
close (WORDSLIST);
}
Tôi đặt nó vào một chương trình con để cho tôi có thể giữ phần chính của chương trình không bị lộn xộn. Điều này cũng có nghĩa là vào thời điểm sau (hướng dẫn: một vài lần ôn lại cuộc đi dạo này), tôi có thể thay đổi nơi cất giữ danh sách từ, hay thậm chí định dạng của danh sách.
Định dạng được chọn bất kì cho danh sách từ là một khoản mục trên một dòng, với tên và từ, luân phiên. Cho nên, với cơ sở dữ liệu hiện tại của chúng ta, chúng ta có cái tựa như thế này:
fred
camel
barney
llama
betty
oyster
wilma
oyster
Toán tử open() tạo ra một tước hiệu tệp có tên WORDSLIST bằng cách liên kết nó với một tệp mang tên wordslist trong danh mục hiện tại. Lưu ý rằng tước hiệu tệp không có kí tự là lạ phía trước nó như ba kiểu biến vẫn có. Cũng vậy, tước hiệu tệp nói chung là chữ hoa - mặc dầu chúng không nhất thiết phải là như thế - bởi những lí do sẽ nêu chi tiết về sau.
Chu trình while đọc các dòng từ tệp wordslist (qua tước hiệu tệp WORDSLIST) mỗi lần một dòng. Mỗi dòng đều được cất giữ trong biến $name. Khi đạt đến cuối tệp thì giá trị cho lại bởi toán tử là xâu rỗng** Về mặt kĩ thuật thì đấy lại là undef, nhưng cũng đủ gần cho thảo luận này , mà sẽ sai cho cho trình while, và kết thúc nó. Đó là cách chúng ta đi ra ở cuối.
Mặt khác, trường hợp thông thường là ở chỗ chúng ta đã đọc một dòng (kể cả dấu dòng mới) vào trong $name. Trước hết, ta bỏ dấu dòng mới bằng việc dùng toán tử chop(). Rồi, ta phải đọc dòng tiếp để lấy từ bí mật, giữ nó trong biến $word. Nó nữa cũng phải bỏ dấu dòng mới đi.
Dòng cuối cùng của chu trình while đặt $word vào trong %words với khoá $name, cho nên phần còn lại của chương trình có thể thâm nhập vào nó về sau.
Một khi tệp đã được đọc xong thì có thể bỏ tước hiệu tệp bằng toán tử close(). (Tước hiệu tệp dẫu sao cũng được tự động đóng lại khi chương trình thoát ra, nhưng tôi đang định làm cho gọn.)

_________________
..................................................................................
nhocyeu_ufa
..................................................................................

Hình ảnhHình ảnh


album1 - hình chụp với Ubuntu
album2 - ảnh cá nhân & bên ngoài


Sửa lần cuối bởi nhocyeu_ufa vào ngày T.Năm Tháng 11 22, 2007 9:47 am với 1 lần sửa.

Đầu trang
 Xem thông tin cá nhân  
 
Gửi bàiĐã gửi: T.Năm Tháng 11 22, 2007 9:39 am 
Đóng góp tích cực
Hình đại diện của thành viên

Ngày tham gia: T.Tư Tháng 11 21, 2007 1:22 pm
Bài viết: 264
Đến từ: Viet Nam
Nhocyeu_ufa lượm lặt gần xa

Định nghĩa chương trình con này có thể đi sau hay trước chương trình con khác. Và chúng ta gọi tới chương trình con thay vì đặt %words vào chỗ bắt đầu của chương trình, cho nên một cách để bao bọc tất cả những điều này có thể giống thế này:
#! /usr/bin/perl
&init_words;
print “Tên bạn là gì?” ;
$name = ;
chop($name);
if ($name =~ /^randal\b/i ) {  #  trở lại cách khác
print “Xin chào, Randal! May quá anh ở đây!\n”;
} else {
print “Xin chào, $original_name!\n”;  # chào thông thường
print “Từ bí mật là gì?” ;
$guess = ;
chop($guess);
while ( ! &good_word($name, $guess))  { 
  print “Sai rồi, thử lại đi. Từ bí mật là gì?”;
  $guess = ;
  chop($guess);
}
}
##  chương trình con từ đây xuống
sub  init_words  {
open (WORDSLIST, “wordslist”);
while ($name = )  {
  chop ($name);
  $word = ;
  chop($word);
  $words{$name} = $word;
}
close (WORDSLIST);
}
sub good_word  {
local($somename, $someguess) = @_; #  tên tham biến
$somename =~ s/\W.*//;  #  bỏ mọi thứ sau từ đầu
$somename =~ tr/A-Z/a-z/;  #  mọi thứ thành chữ thường
if  ($somename eq “randal”)  {  #  không nên đoán
  1;  #giá trị cho lại là true
} elsif (($words{$somename} || “đồ cáu kỉnh”) eq $someguess)  {
  1;  #  giá trị cho lại là true
}  else  {
  0;  #  cho lại giá trị false
}
}
Bây giờ nó bắt đầu trông giống một chương trình trưởng thành hoàn toàn. Chú ý đến dòng thực hiện được đầu tiên là lời gọi tới &init_words. Không có tham biến nào được truyền cả, cho nên chúng ta được tự do bỏ đi dấu ngoặc tròn. Cũng vậy, giá trị cho lại không được dùng trong tính toán thêm, thì cũng là tốt vì ta đã không cho lại điều gì đáng để ý. (Giá trị của close() thông thường là đúng.)
Toán tử open() cũng được dùng để mở các tệp đưa ra, hay mở chương trình như tệp (đã được biểu diễn ngắn gọn). Tuy thế, việc vét hết về open() sẽ được nêu về sau trong cuốn sách này, trong Chương 10, Tước hiệu tệp và kiểm tra tệp.
Đảm bảo một lượng an toàn giản dị
“Danh sách các từ bí mật phải thay đổi ít nhất một lần mỗi tuần!” ông Trưởng ban danh sách từ bí mật kêu lên. Thôi được, chúng ta không thể buộc danh sách này khác đi, nhưng chúng ta có thể ít nhất cũng đưa ra một cảnh báo nếu danh sách từ bí mật còn chưa được thay đổi trong hơn một tuần.
Cách tốt nhất để làm điều này là trong chương trình con &init_words - chúng ta đã nhìn vào tệp ở đó. Toán tử Perl -M cho lại tuổi tính theo ngày từ một tệp hay tước hiệu tệp đã được thay đổi từ lần trước, cho nên ta chỉ cần xem liệu giá trị này có lớn hơn bẩy hay không đối với tước hiệu tệp WORDSLIST:
sub  init_words  {
open (WORDSLIST, “wordslist”);
if  (-M WORDSLIST > 7)  {  #  tuân thủ theo đường lối quan liêu
  die “Rất tiếc, danh sách từ cũ hơn bẩy ngày rồi.”;
}
while ($name = )  {
  chop ($name);
  $word = ;
  chop($word);
  $words{$name} = $word;
}
close (WORDSLIST);
}
Giá trị của -M WORDSLIST được so sánh với bẩy, và nếu lớn hơn, thế thì ta vi phạm vào đường lối rồi. Tại đây, ta thấy một toán tử mới, toán tử die, mà cho in ra một thông báo trên thiết bị cuối** Thực tại là STDERR, nhưng đấy thông thường là màn hình , và bỏ chương trình trong một cú bổ nhào rơi xuống.
Phần còn lại của chương trình vẫn không đổi, cho nên trong mối quan tâm tới việc tiết kiệm cây cối, tôi sẽ không lặp lại nó ở đây.
Bên cạnh việc lấy tuổi của tệp, ta cũng có thể tìm ra người chủ của nó, kích cỡ, thời gian thâm nhập, và mọi thứ khác mà UNIX duy trì về tệp. Nhiều điều hơn được trình bầy trong Chương 10.
Cảnh báo ai đó khi mọi việc đi sai
Ta hãy xem ta có thể làm cho hệ thống bị sa lầy thế nào khi ta gửi một mẩu thư điện tử mỗi lần cho một ai đó đoán từ bí mật của họ không đúng. Ta cần sửa đổi mỗi chương trình con &good_word (nhờ có tính mô đun) vì ta có tất cả thông tin ngay đây.
Thư sẽ được gửi cho bạn nếu bạn gõ địa chỉ thư của riêng mình vào chỗ mà chương trình nói “Địa chỉ bạn ở đây.” Đây là điều ta phải làm - ngay trước khi trả 0 về từ chương trình con, ta tạo ra một tước hiệu tệp mà thực tại là một tiến trình (mail), giống như:
sub  good_word  {
local($somename, $someguess) = @_; #  tên tham biến
$somename =~ s/\W.*//;  #  bỏ mọi thứ sau từ đầu
$somename =~ tr/A-Z/a-z/;  #  mọi thứ thành chữ thường
if  ($somename eq “randal”)  {  #  không nên đoán
  1;  #giá trị cho lại là true
} elsif (($words{$somename} || “đồ cáu kỉnh”) eq $someguess)  {
  1;  #  giá trị cho lại là true
}  else  {
  open(MAIL, “|mail  Địa_chỉ_bạn_ở_đây”);
            print MAIL “tin xấu: $somename đã đoán $someguess\n”;
  0;  #  cho lại giá trị false
}
}
Câu lệnh mới thứ nhất ở đây là open(), mà có một kí hiệu đường ống (|) trong tên tệp. Đây là một chỉ dẫn đặc biệt rằng ta đang mở một chỉ lệnh thay vì một tệp. Vì đường ống là tại chỗ bắt đầu của chỉ lệnh nên ta đang mở  một chỉ lệnh để ta có thể ghi lên nó. (nếu bạn đặt đường ống tại cuối thay vì đầu thì bạn có thể đọc cái ra của chỉ lệnh.)
Câu lệnh tiếp, print, chỉ ra rằng một tước hiệu tệp giữa từ khoá print và giá trị được in ra chọn tước hiệu tệp đó làm cái ra, thay vì STDOUT** Về mặt kĩ thuật thì tước hiệu tệp này hiện được chọn. Điều đó sẽ được nói nhiều tới về sau. . Điều này có nghĩa là thông báo sẽ kết thúc như cái vào cho chỉ lệnh mail.
Cuối cùng, ta đóng tước hiệu tệp, mà sẽ bắt đầu để mail gửi dữ liệu của nó theo cách của nó.
Để cho đúng, chúng ta có thể gửi câu trả lời đúng cũng như câu trả lời sai, nhưng rồi ai đó đọc qua vai tôi (hay núp trong hệ thống thư) trong khi tôi đang đọc thư mà có thể lấy quá nhiều thông tin có ích.
Perl có thể cũng gọi cả các lệnh với việc kiểm soát chính xác trên danh sách đối, mở các tước hiệu tệp, hay thậm chí lôi ra cả bản sao của chương trình hiện tại, và thực hiện hai (hay nhiều) bản sao song song. Backquotes (giống như backquotes của vỏ) cho một cách dễ dàng nắm được cái ra của một chỉ lệnh như dữ liệu. Tất cả những điều này sẽ được mô tả trong Chương 14, Quản lí tiến trình, cho nên bạn nhớ đọc.
Nhiều tệp từ bí mật trong danh mục hiện tại
Ta hãy thay đổi định nghĩa của tên tệp từ bí mật một chút. Thay vì tệp được đặt tên là wordslist, thì ta hãy tìm bất kì cái gì trong danh mục hiện tại mà có tận cùng là .secret. Với lớp vỏ, ta nói:
echo *.secret
để thu được một liệt kê ngắn gọn cho tất cả các tên này. Như lát nữa bạn sẽ thấy, Perl dùng một cú pháp tên chùm tương tự.
Ta lấy lại định nghĩa &init_words :
sub  init_words  {
while ($filename = <*.secret>)  {
  open (WORDSLIST, $filename);
  if  (-M WORDSLIST > 7)  {
   while ($name = )  {
    chop ($name);
    $word = ;
    chop($word);
    $words{$name} = $word;
   }
  }
  close (WORDSLIST);
}
}
Trước hết, tôi đã bao một chu trình while mới quanh phần lớn chương trình con của bản cũ. Điều mới ở đây là toán tử <*.secret>. Điều này được gọi là núm tên tệp, bởi lí do lịch sử. Nó làm việc rất giống , ở chỗ mỗi lần được thâm nhập tới, nó đều cho lại giá trị tiếp: tên tệp kế tiếp sánh với mẫu của vỏ, trong trường hợp này là *.secret. Khi không có tên tệp thêm nữa được cho lại thì núm tên tệp cho xâu rỗng** Lại undef lần nữa .
Cho nên nếu danh mục hiện tại có chứa fred.secret và barney.secret, thì $filename là barney.secret ở bước đầu qua chu trình while (tên tới theo trật tự sắp của bảng chữ). Ở bước thứ hai, $filename là fred.secret. Và không có tình huống thứ ba vì núm cho lại xâu rỗng khi lần thứ ba được gọi tới, làm cho chu trình while thành sai, gây ra việc ra khỏi chương trình con.
Bên trong chu trình while, chúng ta mở tệp và kiểm chứng rằng nó đủ gần đây (ít hơn bẩy ngày từ lần sửa đổi trước). Với những tệp đủ gần, chúng ta duyệt qua như trước.
Chú ý rằng nếu không có tệp nào sánh với *.secret và lại ít hơn bẩy ngày thì chương trình con sẽ ra mà không đặt bất kì từ bí mật nào vào mảng %words. Điều đó có nghĩa là mọi người sẽ phải dùng từ đồ cáu kỉnh. Thế cũng được. (Với mã thật, tôi sẽ thêm một kiểm tra nào đó về số các ô trong %words trước khi cho lại, và die nếu nó không tốt. Bạn hãy xem toán tử keys() khi ta lấy mảng kết hợp trong Chương 5, Mảng kết hợp.)
Nhưng chúng ta biết họ là ai!
Được rồi, chúng ta đã hỏi tên người dùng khi trong thực tế chúng ta có thể lấy tên của người dùng hiện tại từ hệ thống, bằng việc dùng một vài dòng như:
@password = getpwuid($<);  #  lấy dữ liệu mật hiệu
$name = $password[6];  #  lấy trường GCOS
$name =~ s/,.*//;  #  vứt đi mọi thứ sau dấu phẩy đầu tiên
Dòng đầu tiên dùng số hiệu người dùng ID của UNIX (thường được gọi là UID), tự động hiện diện trong biến Perl $<. Toán tử getpwuid() (được đặt tên giống như trình thư viện chuẩn) lấy số hiệu UID và cho lại thông tin từ tệp mật hiệu (hay có thể một số cơ sở dữ liệu khác) như một danh sách. Chúng ta đánh dấu thông tin này trong mảng @password.
Khoản mục thứ bẩy của mảng @password (chỉ số 6) là trường GCOS, mà thường là một xâu có chứa danh sách các giá trị các nhau bởi dấu phẩy. Giá trị đầu tiên của xâu đó thường là tên đầy đủ của người.
Một khi hai câu lệnh đầu này đã hoàn tất thì chúng ta có toàn bộ trường GCOS trong $name. Tên đầy đủ chỉ là phần thứ nhất của xâu trước dấu phẩy đầu tiên, cho nên câu lệnh thứ ba vứt đi mọi thứ sau dấu phẩy thứ nhất.
Gắn tất cả những điều đó với phần còn lại của chương trình (như đã được sửa bởi hai thay đổi chương trình con khác)
#! /usr/bin/perl
&init_words;
@password = getpwuid($<);  #  lấy dữ liệu mật hiệu
$name = $password[6];  #  lấy trường GCOS
$name =~ s/,.*//;  #  vứt đi mọi thứ sau dấu phẩy đầu tiên
if ($name =~ /^randal\b/i ) {  #  trở lại cách khác
print “Xin chào, Randal! May quá anh ở đây!\n”;
} else {
print “Xin chào, $name!\n”;  # chào thông thường
print “Từ bí mật là gì?” ;
$guess = ;
chop($guess);
while ( ! &good_word($name, $guess))  { 
  print “Sai rồi, thử lại đi. Từ bí mật là gì?”;
  $guess = ;
  chop($guess);
}
}

sub  init_words  {
while ($filename = <*.secret>)  {
  open (WORDSLIST, $filename);
  if  (-M WORDSLIST > 7)  {
   while ($name = )  {
    chop ($name);
    $word = ;
    chop($word);
    $words{$name} = $word;
   }
  }
  close (WORDSLIST);
}
}
sub  good_word  {
local($somename, $someguess) = @_; #  tên tham biến
$somename =~ s/\W.*//;  #  bỏ mọi thứ sau từ đầu
$somename =~ tr/A-Z/a-z/;  #  mọi thứ thành chữ thường
if  ($somename eq “randal”)  {  #  không nên đoán
  1;  #giá trị cho lại là true
} elsif (($words{$somename} || “đồ cáu kỉnh”) eq $someguess)  {
  1;  #  giá trị cho lại là true
}  else  {
  open(MAIL, “|mail  Địa_chỉ_bạn_ở_đây”);
            print MAIL “tin xấu: $somename đã đoán $someguess\n”;
  0;  #  cho lại giá trị false
}
}
Chú ý rằng chúng ta không còn cần hỏi người dùng về tên người ấy nữa - chúng ta đã biết nó!
Perl cung cấp nhiều trình thâm nhập cơ sở dữ liệu hệ thống để lôi ra những giá trị từ cơ sở dữ liệu mật hiệu, nhóm, máy chủ, mạng, dịch vụ và giao thức. Cả việc tra cứu riêng (như được trình bầy ở trên) và việc duyệt số lớn cũng đều được Perl hỗ trợ.
Liệt kê các từ bí mật
Rồi ông phụ trách danh sách từ bí mật lại muốn có một báo cáo về tất cả những từ bí mật hiện đang dùng, và chúng cũ đến đâu. Nếu ta gạt sang bên chương trình từ bí mật một lúc, thì ta sẽ có thời gian để viết một chương trình báo cáo cho ông phụ trách.
Trước hết, ta hãy lấy ra tất cả các từ bí mật, bằng việc ăn cắp một đoạn mã trong chương trình con &init_words:
while ($filename = <*.secret>)  {
  open (WORDSLIST, $filename);
  if  (-M WORDSLIST > 7)  {
   while ($name = )  {
    chop ($name);
    $word = ;
    chop($word);
###   chất liệu mới sẽ đưa vào đây
   }
  }
  close (WORDSLIST);
}
Tại điểm có đánh dấu “chất liệu mới sẽ đưa vào đây,” ta biết ba điều: tên của tệp (trong $filename), tên một ai đó (trong $name), và rằng từ bí mật của một người (trong $Word). Sau đây là chỗ để dùng công cụ sinh báo cáo của Perl. Ta định nghĩa một định dạng ở đâu đó trong chương trình (thông thường gần cuối, giống như chương trình con):
format STDOUT =
@<<<<<<<<<<<<<<< @<<<<<<<<<< @<<<<<<<<<<<<<<
$filename, $name, $word
.
Định nghĩa định dạng này bắt đầu với format STDOUT =, và kết thúc với một dấu chấm. Hai dòng ở giữa là chính định dạng. Dòng đầu của định dạng này là dòng định nghĩa trường vốn xác định số lượng, chiều dài và kiểu của trường. Với định dạng này, chúng ta có ba trường. Dòng đi sau dòng định nghĩa trường bao giờ cũng là dòng giá trị trường. Dòng giá trị cho một danh sách các biểu thức mà sẽ được tính khi định dạng này được dùng, và kết quả của những biểu thức đó sẽ được gắn vào trong các trường đã được xác định trên dòng trước đó.
Ta gọi định dạng này với toán tử write, như thế này:
#!/usr/bin/perl
while  ($filename = <*.secret>)  {
open (WORDSLIST, $filename);
if (-M WORDSLIST < 7)  {
     while  ($name = )  {
  chop($name);
  $word =
  chop($word);
  write;  #  gọi định dạng STDOUT tới STDOUT
     }
}
close (WORDSLIST)
}
format STDOUT =
@<<<<<<<<<<<<<<< @<<<<<<<<<< @<<<<<<<<<<<<<<
$filename, $name, $word
.
Khi định dạng này được gọi tới, thì Perl sẽ tính các biểu thức trường và sinh ra một dòng mà nó gửi ra tước hiệu tệp STDOUT. Vì write là được gọi một lần mỗi khi đi qua chu trình nên ta sẽ thu được một loạt các dòng với văn bản theo cột, mỗi dòng cho một từ bí mật.

_________________
..................................................................................
nhocyeu_ufa
..................................................................................

Hình ảnhHình ảnh


album1 - hình chụp với Ubuntu
album2 - ảnh cá nhân & bên ngoài


Sửa lần cuối bởi nhocyeu_ufa vào ngày T.Năm Tháng 11 22, 2007 9:49 am với 1 lần sửa.

Đầu trang
 Xem thông tin cá nhân  
 
Gửi bàiĐã gửi: T.Năm Tháng 11 22, 2007 9:41 am 
Đóng góp tích cực
Hình đại diện của thành viên

Ngày tham gia: T.Tư Tháng 11 21, 2007 1:22 pm
Bài viết: 264
Đến từ: Viet Nam
Nhocyeu_ufa lượm lặt gần xa

Chúng ta còn chưa có nhãn cho các cột. Mà điều đó thì cũng dễ thôi. Ta chỉ cần thêm vào định dạng trên đầu trang, như:
format STDOUT_TOP =
Page @<<
$%

Tên tệp            Tên              Từ
========== ======== ==========
.
Định dạng này mang tên STDOUT_TOP, và sẽ được dùng đầu tiên ngay khi gọi tới địn hdạng STDOUT, rồi lại sau 60 lần đưa ra STDOUT thì nó lại được sinh ra. Các tiêu đề cột ở đây thẳng hàng với các cột trong định dạng STDOUT, cho nên mọi thứ khớp vào nhau.
Dòng đầu tiên trong định dạng này chỉ ra một văn bản hằng nào đó (Page) cùng với việc định nghĩa trường ba kí tự. Dòng sau là dòng giá trị trường, ở đây với một biểu thức. Biểu thức này là biến $%, giữ số trang được in ra - một giá trị rất có ích trong định dạng đầu trang.
Dòng thứ ba của định dạng này để trống. Vì dòng này không chứa bất kì trường nào nên dòng sau nó không phải là dòng giá trị trường. Dòng trống này được sao trực tiếp lên cái ra, tạo ra một dòng trống giữa số trang và tiêu đề cột dưới.
Hai dòng cuối của định dạng này cũng không chứa trường nào, cho nên chúng được sao trực tiếp ra cái ra. Do vậy định dạng này sinh ra bốn dòng, một trong đó có một phần bị thay đổi qua mỗi trang.
Chỉ cần thêm định nghĩa này vào chương trình trước là nó làm việc. Perl để ý đến định dạng đầu trang tự động.
Perl cũng có các trường được định tâm hay căn lề phải, và hỗ trợ cho miền đoạn được rót kín. Sẽ có nhiều vấn đề về điều này hơn khi ta đi vào các định dạng trong Chương 11, Định dạng.
Làm cho danh sách từ cũ đó đáng lưu ý hơn
Khi ta đọc qua các tệp *.secret trong danh mục hiện tại, ta có thể tìm thấy các tệp quá cũ. Cho tới nay, ta đơn thuần nhẩy qua những tệp này. Ta hãy đi thêm một bước nữa - ta sẽ đổi tên chúng thành *.secret.old để cho ls của danh mục sẽ nhanh chóng cho ta những tệp nào quá cũ, đơn thuần theo tên.
Sau đây là cách thức thể hiện cho chương trình con &init_words với sửa đổi này:
sub  init_words  {
while ($filename = <*.secret>)  {
  open (WORDSLIST, $filename);
  if  (-M WORDSLIST > 7)  {
   while ($name = )  {
    chop ($name);
    $word = ;
    chop($word);
    $words{$name} = $word;
   }
  } else  {  #  đổi tên tệp để nó đáng để ý hơn
   rename($filename, “$filename.old”);
  }
  close (WORDSLIST);
}
}
Bạn hãy chú đến phần else mới của việc kiểm tra tuổi. Nếu tệp cũ hơn bẩy ngày, thì nó sẽ được đổi tên bằng toán tử rename(). Toán tử này lấy hai tham biến, đổi tệp có tên trong tham biến thứ nhất thành tên trong tham biến thứ hai.
Perl có một phạm vi đầy đủ các toán tử thao tác tệp - gần như bất kì cái gì bạn có thể thực hiện cho một tệp trong chương trình C, bạn cũng có thể làm từ Perl.

Duy trì một cơ sở dữ liệu đoán đúng cuối cùng
Ta hãy giữ lại dấu vết khi nào việc đoán đúng gần nhất đã được thực hiện cho mỗi người dùng. Một cấu trúc dữ liệu mà dường như mới thoáng nhìn thì có vẻ được là mảng kết hợp. Chẳng hạn, câu lệnh:
$last_good{$name} = time ;
gán thời gian UNIX hiện tại (một số nguyên lớn quãng 700 triệu, chỉ ra số giây) cho một phần tử  của %last_good mà có tên với khoá đó. Qua thời gian, điều này sẽ dường chư cho ta một cơ sở dữ liệu chỉ ra thời điểm gần nhất mà từ bí mật đã được đoán đúng cho từng người dùng đã gọi tới chương trình này.
Nhưng, mảng lại không tồn tại giữa những lần gọi chương trình. Mỗi lần chương trình này được gọi thì một mảng mới lại được hình thành, cho nên nhiều nhất thì ta tạo ra được mảng một phần tử và rồi lập tức lại quên mất nó khi chương trình ra.
Toán tử dbmopen() ánh xạ một mảng kết hợp vào một tệp đĩa (thực tế là một cặp tệp đĩa) được xem như một DBM. Nó được dùng như thế này:
dbmopen(%last_good, “lastdb”, 066);
$last_good($name) = time;
dbmclose(%last_good);
Câu lệnh đầu tiên thực hiện việc ánh xạ này, dùng các tên tệp đĩa của lastdb.dir và lastdb.pag (các tên này là tên thông thường cho DBM được gọi là lastdb). Các phép về tệp UNIX được dùng cho hai tệp này nếu các tệp đó phải được tạo ra (khi chúng lần đầu tiên được gặp tới) là 0666. Mốt này có nghĩa là bất kì ai cũng có thể đọc hay ghi lên tệp. (Các bit phép tệp được mô tả trong manpage chmod(2).)
Câu lệnh thứ hai chỉ ra rằng chúng ta dùng mảng kết hợp đã được ánh xạ này hệt như mảng kết hợp thông thường. Tuy nhiên, việc tạo ra hay cập nhật một phần tử của mảng sẽ tự động cập nhật tệp đĩa tạo nên DBM. Và, khi mảng được thâm nhập tới lần cuối thì giá trị bên trong mảng sẽ tới trực tiếp từ hình ảnh đĩa.  Điều này cho mảng kết hợp một cuộc sống trải bên ngoài lời gọi hiện thời của chương trình - một sự bền lâu của riêng nó.
Câu lệnh thứ ba ngắt mảng kết hợp ra khỏi DBM, giống hệt thao tác đóng tệp close().
Bạn có thể chèn thêm ba câu lệnh này vào ngay đầu các định nghĩa chương trình con.
Mặc dầu các câu lệnh được chèn thêm này duy trì cơ sở dữ liệu là tốt (và thậm chí còn tạo ra nó trong lần đầu), chúng ta vẫn không có cách nào để xem xét thông tin trong đó. Để làm điều đó, ta có thể tạo ra một chương trình nhơ tách biệt trông đại thể như thế này:
#!/usr/bin/perl
dbmopen(%last_good, “lastdb”, 0666);
foreach $name (sort keys(%last_good)  {
$when = $last_good{$name};
$hours = (time - $when) / 3600;  #  tính giờ đã qua
write;
}
format STDOUT =
User @<<<<<<<<<<: br="" c="" cu="" gi="" i="" l="" n="" ng="" o="" qua.="">$name, $hour
.
Chúng ta có vài toán tử mới ở đây: chu trình foreach, sắp xếp một danh sách, và lấy khoá của mảng.
Trước hết, toán tử keys() lấy một tên mảng kết hợp như một đối và cho lại một danh sách tất cả các khoá của mảng đó theo một thứ tự không xác định nào đó. (Điều này hệt như toán tử keys trong awk.) Với mảng %words được xác định trước đây, kết quả là một cái gì đó tựa như fred, barney, betty, wilma, theo một thứ tự không xác định. Với mảng %last_good, kết quả sẽ là một danh sách của tất cả người dùng đã đoán thành công từ bí mật của riêng mình.
Toán tử sort sẵp xếp theo thứ tự bảng chữ (hệt như việc truyền một tệp văn bản qua chỉ lệnh sort). Điều này bảo đảm rằng danh sách được xử lí bởi câu lệnh foreach  bao giờ cũng theo thứ tự bảng chữ.
Thân của chu trình foreach nạp vào hai biến được dùng trong định dạng STDOUT, và rồi gọi tới định dạng đó. Chú ý rằng chúng ta đoán ra tuổi của một phần tử bằng cách trừ thời gian UNIX đã cất giữ (trong mảng) từ thời gian hiện tại (như kết quả của time) và rồi chia cho 3600 (để chuyển từ giây sang giờ).
Perl cũng cung cấp những cách thức dễ dàng để tạo ra và duy trì các cơ sở dữ liệu hướng văn bản (như tệp mật hiệu) và cơ sở dữ liệu bản ghi chiều dài cố định (như cơ sở dữ liệu “đăng nhập lần cuối” do chương trình login duy trì). Những cơ sở dữ liệu này sẽ được mô tả trong Chương 17, Thao tác cơ sở dữ liệu người dùng.
Chương trình cuối cùng
Sau đây là chương trình mà cuộc đi dạo này đã đưa tới dưới dạng cuối cùng để bạn có thể chơi với chúng.
Trước hết là chương trình “nói lời chào”:
#! /usr/bin/perl
&init_words;
@password = getpwuid($<);  #  lấy dữ liệu mật hiệu
$name = $password[6];  #  lấy trường GCOS
$name =~ s/,.*//;  #  vứt đi mọi thứ sau dấu phẩy đầu tiên
if ($name =~ /^randal\b/i ) {  #  trở lại cách khác
print “Xin chào, Randal! May quá anh ở đây!\n”;
} else {
print “Xin chào, $name!\n”;  # chào thông thường
print “Từ bí mật là gì?” ;
$guess = ;
chop($guess);
while ( ! &good_word($name, $guess))  { 
  print “Sai rồi, thử lại đi. Từ bí mật là gì?”;
  $guess = ;
  chop($guess);
}
}

dbmopen(%last_good, “lastdb”, 066);
$last_good($name) = time;
dbmclose(%last_good);
sub  init_words  {
while ($filename = <*.secret>)  {
  open (WORDSLIST, $filename);
  if  (-M WORDSLIST > 7)  {
   while ($name = )  {
    chop ($name);
    $word = ;
    chop($word);
    $words{$name} = $word;
   }
  }
  close (WORDSLIST);
}
}
sub  good_word  {
local($somename, $someguess) = @_; #  tên tham biến
$somename =~ s/\W.*//;  #  bỏ mọi thứ sau từ đầu
$somename =~ tr/A-Z/a-z/;  #  mọi thứ thành chữ thường
if  ($somename eq “randal”)  {  #  không nên đoán
  1;  #giá trị cho lại là true
} elsif (($words{$somename} || “đồ cáu kỉnh”) eq $someguess)  {
  1;  #  giá trị cho lại là true
}  else  {
  open(MAIL, “|mail  Địa_chỉ_bạn_ở_đây”);
            print MAIL “tin xấu: $somename đã đoán $someguess\n”;
  0;  #  cho lại giá trị false
}
}
Tiếp đó, ta có bộ in từ bí mật:
#! /usr/bin/perl
while ($filename = <*.secret>)  {
open (WORDSLIST, $filename);
if  (-M WORDSLIST > 7)  {
  while ($name = )  {
   chop ($name);
   $word = ;
   chop($word);
   write;  #  gọi định dạng STDOUT cho STDOUT
  }
}
close(WORDSLIST);
}
format STDOUT =
@<<<<<<<<<<<<<<< @<<<<<<<<<< @<<<<<<<<<<<<<<
$filename, $name, $word
.
format STDOUT_TOP =
Page @<<
$%

     Tên tệp             Tên                Từ
========== ======== ==========
.
Và cuối cùng, là chương trình hiển thị từ đã được dùng lần cuối cùng:
#!/usr/bin/perl
dbmopen(%last_good, “lastdb”, 0666);
foreach $name (sort keys(%last_good)  {
$when = $last_good{$name};
$hours = (time - $when) / 3600;  #  tính giờ đã qua
write;
}
format STDOUT =
User @<<<<<<<<<<: br="" c="" cu="" gi="" i="" l="" n="" ng="" o="" qua.="">$name, $hour
.
Cùng với danh sách từ bí mật (các tệp có tên something.secret trong danh mục hiện tại) và cơ sở dữ liệu lastdb.dir và lastdb.pag, bạn đã có tất cả những gì mình cần.

Bài tập
Thông thường, mỗi chương sẽ kết thúc với một số bài tập, lời giải cho chúng sẽ có trong Phụ lục A, Trả lời bài tập. Với chuyến đi dạo này, lời giải đã được cho ở trên.
1. Hãy gõ trong chương trình thí dụ trên vào máy rồi cho nó chạy. (Bạn cần tạo ra danh sách từ bí mật nữa.) Hãy hỏi thầy Perl của mình nếu bạn cần trợ giúp

_________________
..................................................................................
nhocyeu_ufa
..................................................................................

Hình ảnhHình ảnh


album1 - hình chụp với Ubuntu
album2 - ảnh cá nhân & bên ngoài


Sửa lần cuối bởi nhocyeu_ufa vào ngày T.Năm Tháng 11 22, 2007 9:51 am với 1 lần sửa.

Đầu trang
 Xem thông tin cá nhân  
 
Gửi bàiĐã gửi: T.Năm Tháng 11 22, 2007 5:51 pm 
Sáng lập Ubuntu-VN
Hình đại diện của thành viên

Ngày tham gia: T.Tư Tháng 8 09, 2006 9:14 pm
Bài viết: 130
Trong doanh nghiệp hiện tại mình làm việc, Perl được sử dụng rất nhiều trong việc "tự động hóa", có nghĩa là các script để thực thi việt build phần mềm, update SVN, quản lý, backup tài liệu. Thiếu các script này, công việc sẽ nặng hơn nhiều. Mỗi khi làm xong một phần mềm gì, chỉ cần click, click là đã có build package rồi, không phải chỉ thông số này thông số nọ, thư mục này thư mục kia.

Ngoài ra, thêm thông tin cho ai đang phát triển phần mềm di động : Perl là một định hướng mới đối với Nokia trên nền Symbian, vì thế, sau này, Perl sẽ rất được ưa chuộng.

Cuốn sách trên của em hay nhưng chỉ là "nhập môn" thôi. Ai muốn tìm học lập trình Perl thì phải đọc nhiều hơn nữa.

Cảm ơn em.


Đầu trang
 Xem thông tin cá nhân  
 
Gửi bàiĐã gửi: T.Ba Tháng 11 27, 2007 9:30 am 
Đóng góp tích cực
Hình đại diện của thành viên

Ngày tham gia: T.Tư Tháng 11 21, 2007 1:22 pm
Bài viết: 264
Đến từ: Viet Nam
Thì nhóc mới nhập môn mà, nền chưa vững thì bước tiếp bước nào cũng "tuột". Sách này tương đối chi tiết cho người mới. Dễ dàng hiểu lúc bắt đầu thì sau này lập trình vững hơn.

_________________
..................................................................................
nhocyeu_ufa
..................................................................................

Hình ảnhHình ảnh


album1 - hình chụp với Ubuntu
album2 - ảnh cá nhân & bên ngoài


Đầu trang
 Xem thông tin cá nhân  
 
Gửi bàiĐã gửi: T.Ba Tháng 11 27, 2007 10:51 am 
Đóng góp tích cực
Hình đại diện của thành viên

Ngày tham gia: T.Tư Tháng 11 21, 2007 1:22 pm
Bài viết: 264
Đến từ: Viet Nam
Nhócyêu_ufa lượm lặt gần xa


2


Dữ liệu vô hướng


Dữ liệu vô hướng là gì?
Vô hướng là loại dữ liệu đơn giản nhất mà Perl thao tác. Một vô hướng thì hoặc là một số (giống 4 hay 3.25e20) hay một xâu các kí tự (giống Xin chào hay Gettysburg Address). Mặc dầu bạn có thể nghĩ về số và xâu như những vật rất khác nhau, Perl dùng chúng gần như đổi lẫn cho nhau, cho nên tôi sẽ mô tả chúng với nhau.
Một giá trị vô hướng có thể được tác động tới qua các toán tử (giống như phép cộng hay ghép tiếp), nói chung cho lại một kết quả vô hướng. Một giá trị vô hướng có thể được cất giữ vào trong một biến vô hướng. Các vô hướng có thể được đọc từ tệp và thiết bị, và được ghi ra nữa.

Số
Mặc dầu vô hướng thì hoặc là một số hay một xâu, điều cũng có ích là nhìn vào các số và xâu tách biệt nhau trong một chốc. ta sẽ xét số trước rồi đến xâu...
Tất cả các số đều có cùng định dạng bên trong
Như bạn sẽ thấy trong vài đoạn tiếp đây, bạn có thể xác định cả số nguyên (toàn bộ số, giống như 14 hay 342) và số dấu phẩy động (số thực với dấuchấm thập phân, như 3.14, hay 1.35 lần 1025). Nhưng bên trong, Perl chỉ tính với các giá trị dấu phẩy động độ chính xác gấp đôi. Điều này có nghĩa là không có giá trị nguyên bên trong Perl - một hằng nguyên trong chương trình được xử lí như giá trị dấu phẩy động tương đương. Bạn có lẽ không để ý đến việc chuyển đổi (hay quan tâm nhiều), nhưng bạn nên dừng tìm kiếm phép toán nguyên (xem như ngược với các phép toán dấu phẩy động), vì không có tẹo nào.

Hằng kí hiệu động
Hằng kí hiệu là một cách để biểu diễn một giá trị trong văn bản chương trình Perl - bạn cũng có thể gọi điều này là một hằng trong chương trình mình, nhưng tôi sẽ dùng thuật ngữ hằng kí hiệu. Hằng kí hiệu là cách thức biểu diễn dữ liệu trong mã chương trình gốc của chương trình bạn như cái vào cho trình biên dịch Perl. (Dữ liệu được đọc từ hay ghi lên các tệp đều được xử lí tương tự, nhưng không đồng nhất.)
Perl chấp nhận tập hợp đầy đủ các hằng kí hiệu dấu phẩy động có sẵn cho người lập trình C. Số có hay không có dấu chấm thập phân đều được phép (kể cả tiền tố cộng hay trừ tuỳ chọn), cũng như phần chỉ số mũ phụ thêm (kí pháp luỹ thừa) với cách viết E. Chẳng hạn:
1.25 #  một phần tư
7.25e45 #  7.25 lần 10 mũ 45 (một số lớn)
-6.5e24 #  âm 6.5 lần 10 mũ 24 (một số âm lớn)
-12e-24 #  âm 12 lần 10 mũ -24 (một số âm rất nhỏ)
-1.2E-23 #  một cách khác để nói điều đó.

Hằng kí hiệu nguyên
Các hằng kí hiêu jnguyên cũng là trực tiếp, như trong:
12
15
-2004
3485
Bạn đừng bắt đầu một số bằng 0, vì Perl hỗ trợ cho hằng kí hiệu hệ tám và hệ mười sáu (hệt như kiểu C). Số hệ tám bắt đầu bằng số 0 đứng đầu, còn số hệ mười sáu thì bắt đầu bằng 0x hay 0X** Chỉ báo “số không đứng đầu” chỉ có tác dụng với các hằng kí hiệu - không có tác dụng cho việc chuyển đổi tự động xâu sang số. bạn có thể chuyển đổi một xâu dữ liệu giống như một giá trị hệ tám và hệ mười sáu thành một số với oct() hay hex(). . Các chữ số hệ mười sáu A đến F (trong cả hai kiểu chữ hoa thường) đều biểu thị cho các giá trị số qui ước từ 10 đến 15. Chẳng hạn:
0377  #  377 hệ tám, giống như 255 thập phân
-0xff  #  FF hệ mười sáu âm, hệt như -255 thập phân

Xâu
Xâu là các dẫy kí tự (như Xin chào). Mỗi kí tự đều là một giá trị 8-bit trong toàn bộ tâkp 256 kí tự (không có gì đặc biệt về kí tự NUL như trong C).
Xâu ngắn nhất có thể được thì không có kí tự nào. Xâu dài nhất thì chiếm trọn bộ nhớ của bạn (mặc dầu bạn sẽ chẳng thể nào làm gì nhiều với nó cả). Điều này phù hợp với nguyên lí “không có giới hạn sẵn gì” mà Perl cho phép mọi cơ hội. Các xâu điển hình là các dẫy in được gồm các chữ và số và dấu ngắt trong phạm vi ASCII 32 tới ASCII 126. Tuy nhiên, khả năng để có bất kì kí tự nào từ 0 tới 255 trong một xâu có nghĩa là bạn có thể tạo ra, nhòm qua, và thao tác dữ liệu nhị phân thô như các xâu - một cái gì đó mà phần lớn các trình tiện ích UNIX khác sẽ gặp khó khăn lớn. (Chẳng hạn, bạn có thể vá víu lõi UNIX bằng việc đọc nó vào trong xâu Perl, tiến hành thay đổi, và ghi kết quả lại.)
Giống như số, xâu có biểu diễn hằng kí hiệu (cách thức bạn biểu diễn xâu trong chương trình Perl). Các xâu hằng kí hiệu có theo hai hương vị: xâu dấu nháy đơn và xâu dấu nháy kép.

Xâu dấu nháy đơn
Xâu dấu nháy đơn là một dẫy các kí tự được bao trong dấu nháy đơn. Dấu nháy đơn không phải là một phần của bản thân xâu - chúng chỉ có đó để Perl xác định chỗ bắt đầu và kết thúc của xâu. Bất kì kí tự nào nằm giữa các dấu nháy (kể cả dấu dòng mới, nếu xâu vẫn còn tiếp tục sang dòng sau) đều là hợp pháp bên trong xâu. Hai biệt lệ: để lấy được một dấu nháy đơn trong một xâu có nháy đơn, bạn hãy đặt trước nó một dấu sổ chéo ngược. Và để lấy được dấu sổ chéo ngược trong một xâu có nháy đơn, bạn hãy đặt trước dấu sổ chéo ngược nột dấu sổ chéo ngược nữa. Dưới dạng hình ảnh:
hello #  năm kí tự: h, e, l, l, o
dont\t #  năm kí tự: d, o, n, nháy đơn, t
#  xâu không (không kí tự)
silly\\me #  silly, theo sau là một sổ chéo ngược, sau là me
hello\n #  hello theo sau là sổ chéo ngược và n
hello
there #  hello, dòng mới, there (toàn bộ 11 kí tự)
Chú ý rằng \n bên trong môt jxâu có nháy đơn thì không được hiểu là dòng mới, nhưng là hai kí tự sổ chéo ngược và n. (Chỉ khi sổ chéo ngược đi theo sau bởi một sổ chéo ngược khác hay một dấu nháy đơn thì mới mang nghĩa đặc biệt.)

Xâu dấu nháy kép
Xâu dấu nháy kép hành động hệt như xâu trong C. Một lần nữa, nó lại là dãy các kí tự, mặc dầu lần này được bao bởi dấu ngoặc kép. Nhưng bây giờ dấu sổ chéo ngược lấy toàn bộ sức mạnh của nó để xác định các kí tự điều khiển nào đó, hay thậm chí bất kì kí tự nào qua các biểu diễn hệ tám hay hệ mười sáu. Đây là một số xâu dấu nháy kép:
“hello world\n” #  hello world, và dòng mới
“new \177” #  new, dấu cách và kí tự xoá (177 hệ tám)
“coke\tsprite” #  coke, dấu tab, và sprite
Dấu sổ chéo có thể đứng trước nhiều kí tự khác nhau để hàm ý những điều khác nhau (về điển hình nó được gọi là lối thoát sổ chéo). Danh sách đầy đủ của các lối thoát xâu nháy kép được cho trong Bảng 2-1.
Bảng 2-1 Lối thoát sổ chéo ngược xâu nháy kép
Kết cấu Ý nghĩa
\n dòng mới
\r quay lại
\t Tab
\f kéo giấy
\b Backspace
\v tab chiều đứng
\a chuông
\e lối thoát
\007 bất kì giá trị ASCII hệ tám (ở đây, 007 = chuông)
\x7f giá trị ASCII hệ mười sáu (ở đây, 7f = xoá)
\cC bất kì kí tự “điều khiển” nào (ở đây, control C)
\\ sổ chéo ngược
\” dấu nháy kép
\l chữ tiếp là chữ thường
\L tất cả các chữ đi sau cho tới \E đều là chữ thường
\u Chữ tiếp là chữ hoa
\U tất cả các chữ đi sau cho tới \E đều là chữ hoa
\E Kết thúc \L hay \U

Một tính năng khác của xâu nháy kép là ở chỗ chúng cho phép chen lẫn các biến, nghĩa là một số tên biến nào đó bên trong xâu được thay thế bởi giá trị hiện tại của chúng khi xâu được dùng. Chúng ta đã không được giới thiệu một cách chính thức là các biến trông như thế nào (ngoại trừ trong cuộc đi dạo), cho nên tôi sẽ quay lại vấn đề này sau.

Toán tử
Một toán tử tạo ra một giá trị mới (kết quả) từ một hay nhiều giá trị khác (các toán hạng). Chẳng hạn, + là một toán tử vì nó nhận hai số (toán hạng, như 5 và 6), và tạo ra một giá trị mới (11, kết quả).
Các toán tử và biểu thức của Perl nsoi chung đều là siêu tập của các toán tử đã có trong hầu hết các ngôn ngữ lập trình tựa ALGOL/Pascal, như C. Một toán tử bao giờ cũng trông đợi các toán hạng số hay xâu (hay có thể là tổ hợp của cả hai). Nếu bạn cung cấp một toán hạng xâu ở chỗ đang cần tới một số, hay ngược lại, thì Perl sẽ tự động chuyển toán hạng đó bằng việc dùng các qui tắc khá trực giác, mà sẽ được nêu chi tiết trong mục “Chuyển đổi giữa số và xâu,” dưới đây.

Toán tử cho số
Perl cung cấp các toán tử cộng, trừ, nhân, chia điển hình thông thường, vân vân. Chẳng hạn:
2 + 3 #  2 cộng 3, hay 5
5.1 - 2.4 #  5.1 trừ đi 2.4, hay 2.7
3 * 12 #  3 lần 12 = 36
14 / 2 #  14 chia cho 2, hay 7
10.2 / 0.3 #  10.2 chia cho 0.3, hay 34
10 / 3 #  bao giờ là phép chia dấu phẩy động, nên 3.333...
Bên cạnh đó, Perl cung cấp toán tử lũy thừa kiểu FORTRAN, mà nhiều người đã từng mong mỏi cho Pascal và C. Toán tử này được biểu diễn bằng hai dấu sao, như 2**3, chính là hai luỹ thừa ba, hay tám. (Nếu kết quả không thể khớp trong số dấu phẩy động độ chính xác gấp đôi, như một số âm mà lại luỹ thừa theo số không nguyên, hay một số lớn lấy luỹ thừa theo số lớn, thì bạn sẽ nhận được lỗi định mệnh.)
Perl cũng hỗ trợ cho toán tử lấy đồng dư modulus, như trong C. Giá trị của biểu thức 10 % 3  là số dư khi lấy mười chia cho ba, chính là một. Cả hai giá trị đều trước hết được đưa về giá trị nguyên, cho nên 10.5 % 3.2 được tính là 10 % 3.
Các toán tử so sánh logic là hệt như các toán tử có trong C (< <= == >= > !=), và việc so sánh hai giá trị về mặt số sẽ cho lại một giá trị đúng hay sai. Chẳng hạn, 3 . 2 cho lại đúng vì ba lớn hơn hai, trong khi 5 != 5 cho lại sai vì không đúng là năm lại không bằng năm. Các định nghĩa về đúng và sai được nói tới về sau, nhưng với hiện tại, các bạn hãy nghĩ về giá trị cho lại giống như chúng ở trong C - một là đúng, còn không là sai. (Các toán tử này sẽ đwojc thăm lại trong Bảng 2-2.)

Toán tử xâu
Các giá trị xâu có thể được ghép với toán tử chấm (.). (Quả thế, đó là dấu chấm đơn.) Điều này không làm thay đổi xâu, cũng như 2+3 không làm thay đổi 2 hay 3. Xâu kết quả (dài hơn) vậy là có sẵn cho tính toán thêm hay được cất giữ trong một biến.
“hello” . “world” #  hệt như “helloworld”
hello wordl . “\n” #  hệt như “hello world\n”
“fred” . “ “ . “barney” #  hệt như “fred barney”
Chú ý rằng việc ghép nối phải được gọi tường minh tới toán tử ., không giống awk mà bạn đơn thuần phải đánh dấu hai giá trị gần lẫn nhau.
Một tập các toán tử cho xâu khác là toán tử so sánh xâu. Các toán tử này đều tựa FORTRAN, như lt thay cho bé hơn, vân vân. Các toán tử so sánh các giá trị ASCII của các kí tự của xâu theo cách thông thường. Tập đầy đủ các toán tử so sánh (cho cả số và xâu) được nêu trong Bảng 2-2.
Bảng 2-2. Các toán tử so sánh số và xâu
Phép so sánh Số Xâu
Bằng == eq
Không bằng != ne
Bé hơn < lt
Lớn hơn > gt
Bé hơn hay bằng <= le
Lớn hơn hay bằng >= ge

Bạn có thể tự hỏi tại sao lại có các toán tử phân tách cho số và xâu vậy, nếu số và xâu được tự động chuyển đổi lẫn cho nhau. ta hãy xét hai giá trị 7 và 30. Nếu được so sánh như số thì 7 hiển nhiên bé hơn 30, nhưng nếu được so sánh theo xâu, thì xâu “30” sẽ đứng trước xâu “7” (vì giá trị ASCII của 3 thì bé hơn giá trị ASCII của 7), và do đó là bé hơn. Cho nên, không giống awk, Perl đòi hỏi bạn xác định đúng kiểu so sánh, liệu đó là số hay xâu.
Chú ý rằng các phép so sánh số và xâu về đại thể ngược với những điều xẩy ra cho chỉ lệnh test của UNIX, mà thường dùng kí hiệu -eq để so sánh số còn = để so sánh xâu.
Vẫn còn một toán tử xâu khác là toán tử lặp lại xâu, bao gồm một kí tự chứ thường đơn giản x. Toán tử này lấy toán hạng trái của nó (một xâu), và thực hiện nhiều việc ghép bản sao của xâu đó theo số lần do toán hạng bên phải chỉ ra (một số). Chẳng hạn:
“fred” x 3 #  là “fredfredfred”
“barney” x (4+1) #  là “barney” x 5 hay
# “barneybarneybarneybarneybarney”
(3+2) x 4 #  là 5 x 4, hay thực sự “5” x 4, là “5555”
Thí dụ cuối cùng đáng để xem xét chậm rãi. Các dấu ngoặc trên (3+2) buộc cho phàn này của biểu thức cần phải được tính trước, cho năm. (Các dấu ngoặc ở đây làm việc giống như trong C, hay trong toán học chuẩn.) Nhưng toán tử lặp lại xâu cần một xâu cho toán hạng bên trái, cho nên số 5 được chuyển thành xâu “5” (dùng các qui tắc sẽ được mô tả chi tiết về sau), thành xâu một kí tự. Xâu mới này rồi được sao lên bốn lần, cho xâu bốn kí tự 5555. Chú ý rằng nếu ta đảo ngược trật tự các toán hạng, thì tssa sẽ làm năm bản sao của xâu 4, cho 44444. Điều này chỉ ra rằng việc lặp lại xâu là không giao hoán.
Số đếm bản sao (toán hạng bên phải) trước hết sẽ bị chặt cụt đi để cho giá trị nguyên (4.8 trở thành 4) trước khi được sử dụng. Số đếm bản sao bé hơn một sẽ gây ra kết quả là xâu rỗng (chiều dài không).

Thứ tự ưu tiên và luật kết hợp của toán tử
Thứ tự ưu tiên của toán tử xác định ra cách giải quyết trường hợp không rõ ràng khi nào dùng toán tử nào trên ba toán hạng. Chẳng hạn, trong biểu thức 2+3*4, ta sẽ thực hiện phép cộng trước hay phép nhân trước? Nếu ta làm phép cộng trước thì ta sẽ được 5*4, hay 20. Nhưng nếu ta làm phép nhân trước (như ta vẫn được dậy trong giờ toán) thì ta được 2+12, hay 14. May mắn là Perl chọn định nghĩa toán học thông thường, thực hiện nhân trước. Bởi ffiều này, ta nói nhân có số ưu tiên cao hơn cộng.
Bạn có thể phá rào trật tự theo số ưu tiên bằng việc dùng dấu ngoặc. Bất kì cái gì trong dấu ngoặc đều được tính hết trước khi toán tử bên ngoài dấu ngoặc được áp dụng (hệt như bạn đã học trong giờ toán). Cho nên nếu tôi thực sự muốn cộng trước khi nhân, thì tôi có thể viết (2+3)*4, cho 20. Cũng vậy, nếu tôi muốn biểu thị rằng phép nhân được thực hiện trước phép cộng, tôi có thể trang điểm thêm nhưng chẳng để làm gì, một cặp dấu ngoặc trong 2+(3*4).
Trong khi số ưu tiên là trực giác cho phép cộng và nhân thì ta bắt đầu lao vào vấn đề thường hay phải đương đầu với, chẳng hạn, phân biệt thế nào đối với phép ghép xâu và nâng lên luỹ thừa. Các đúng đắn để giải quyết điều này là tra cứu sơ đồ số thứ tự ưu tiên toán tử của Perl, được nêu trong Bảng 2-3. (Chú ý rằng một số các toán tử còn chưa được mô tả, và trong thực tế, thậm chí không thể xuất hiện ở bất kì đâu trong cuốn sách này, nhưng chớ có làm điều đó làm bạn hoảng sợ về việc đọc chúng.) Với những toán tử cũng có trong C, thì những toán tử đó có cùng sóo thứ tự ưu tiên như chúng có trong C (mà tôi có thể chẳng bao giờ nhớ được).
Bảng 2-3: Luật kết hợp và số ưu tiên của các toán tử (thấp nhất đến cao nhất)

Luật kết hợp Toán tử
không Toán tử “danh sách”
trái , (phẩy)
phải += và các toán tử khác (toán tử “gán”)
phải ? : (toán tử if/then/else ba ngôi)
không .. (toán tử phạm vi, cấu tử danh sách)
trái || (hoặc logic)
trái && (và logic)
trái |  ^  (hoặc bit, hoặc bit loại trừ)
trái &  (và bit)
không == != <=> eq ne cmp (toán tử “bằng”)
không <  <=  >  >= lt le gt ge (toán tử “không bằng”)
không Toán tử một ngôi có tên
không -r và (các toán tử kiểm tra tệp)** Perl 5.0 tổ hợp các toán tử kiểm tra tệp và toán tử một ngôi có tên vào cùng mức số ưu tiên khác
trái <<  >>  (dịch chuyển bit)
trái +  -  .  (cộng, trừ, ghép xâu)
trái *  /  %  x  (nhân, chia, lấy dư, lặp xâu)
trái =~  !~  (sánh, không sánh)
phải **  (luỹ thừa)
phải !  ~  -  (phủ định logic, phủ định bit, phủ định số)
không ++  --  (tự tăng, tự giảm)

Trong sơ đồ này, bất kì toán tử đã cho nào đều có số ưu tiên lớn hơn các toán tử được liệt kê trên nó, và có số ưu tiên thấp hơn các toán tử được liệt kê dưới nó. (Điều này dựng ngược lại điều có lẽ bạn đang trông đợi, nhưng nó hệt như trong sách con lừa, và chúng tôi cũng đã dựng ngược nó xuống ở đó nữa.) Các toán tử tại cùng mức ưu tiên được giải quyết theo luật kết hợp.
Giống như với số ưu tiên, luật kết hợp giải quyết trật tự của các phép toán khi hai toán tử có cùng mức ưu tiên cùng tác động trên ba toán hạng:
2 ** 3 ** 4 #  2 ** (3 ** 4), hay 2 ** 81, hay xấp xỉ 2.41e24
72 / 12 / 3 #  (72 / 12) / 3, hay 6 / 3, hay 2
30 / 6 * 3 #  (30/6)*3, hay 15
Trong trường hợp thứ nhất, toán tử ** có luật kết hợp phải, cho nên các dấu ngoặc được áp dụng từ bên phải. So sánh với nó, các toán tử * và / có luật kết hợp trái, cho tập các dấu ngoặc bên trái.

_________________
..................................................................................
nhocyeu_ufa
..................................................................................

Hình ảnhHình ảnh


album1 - hình chụp với Ubuntu
album2 - ảnh cá nhân & bên ngoài


Đầu trang
 Xem thông tin cá nhân  
 
Gửi bàiĐã gửi: T.Ba Tháng 11 27, 2007 10:55 am 
Đóng góp tích cực
Hình đại diện của thành viên

Ngày tham gia: T.Tư Tháng 11 21, 2007 1:22 pm
Bài viết: 264
Đến từ: Viet Nam
Nhócyêu_ufa lượm lặt gần xa


Chuyển đổi giữa số và xâu
Nếu một giá trị xâu được dùng như một toán hạng cho một toán tử số (chẳng hạn, +), thì Perl sẽ tự động chuyển xâu thành giá trị số tương đương, dường như nó đã được đưa vào như một giá trị dấu phẩy động** Các giá trị hệ tám và hệ mười sáu không được hỗ trợ trong chuyển đổi tự động này. Bạn hãy dùng hex() và oct() để diễn giải các giá trị hệ mười sáu và tám. . Những chất liệu phi số đằng đuôi và khoảng trắng đằng đầu đều bị bỏ qua một cách yên lặng và lễ phép, cho nên “  123.45fred” (với dấu cách đứng trước) chuyển thành 123.45 với lời cảnh báo** Trừ phi bạn bật tuỳ chọn -w trên dòng lệnh . Tại một cực điểm của điều này, một cái gì đó không phải là số tẹo nào chuyển thành không mà không có báo trước (như xâu fred được dùng như số).
Giống vậy, nếu một giá trị số được cho khi đang cần tới một giá trị xâu (cho phép ghép xâu chẳng hạn), thì giá trị số sẽ được mở rộng thành bất kì xâu nào sẽ được in ra cho số đó. Chẳng hạn, nếu bạn muốn ghép nối X và theo sau là kết quả của 4 nhân với 5 thì bạn có thể làm đơn giản là:
“X”.(4*5)  #  hệt như  “X”.20, hay “X20”
(Nhớ rằng các dấu ngoặc này buộc 4*5 phải được tính trước khi xem xét toán tử ghép nối xâu.)
Nói cách khác, bạn không thực sự phải lo lắng gì về liệu bạn có một số hay một xâu (phần lớn thời gian). Perl thực hiện mọi chuyển đổi cho bạn.

Biến vô hướng
Một biến là một tên gọi cho một chỗ chứa giữ được một hay nhiều giá trị. Tên của biến là không đổi trong toàn bộ chương trình, nhưng giá trị hay các giá trị được chứa trong biến đó về cơ bản thì lại thay đổi đi thay đổi lại trong suốt sự thực hiện chương trình.
Một biến vô hướng thì giữ một giá trị vô hướng riêng (biểu thị cho một số, hay một xâu, hay cả hai). Các tên biến vô hướng bắt đầu với dấu đô la và tiếp theo sau là một chữ, rồi thì có thể là nhiều chữ, số hay dấu gạch thấp. Chữ hoa và chữ thường là phân biệt: biến $A là khác biến $a. Và tất cả các chữ, số và gạch thấp đều có nghĩa, cho nên:
$a_very_long_variable_that_ends_in_1
là khác với
$a_very_long_variable_that_ends_in_2
Bạn nói chung nên chọn  tên biến mang một nghĩa nào đó có liên quan tới giá trị của biến đó. Chẳng hạn, $xyz123 có lẽ không mang tính mô tả nhiều lắm nhưng $line_length thì lại có nghĩa.

Các toán tử trên biến vô hướng
Phép toán thông dụng nhất trên biến vô hướng là phép gán, chính là cách đặt một giá trị cho một biến. Toán tử gán của Perl là dấu bằng (giống như C hay FORTRAN), để tên biến bên vế trái và cho giá trị của biểu thức bên vế phải, kiểu như:
$a = 17; #  cho $a giá trị 17
$b = $a + 3; #  cho $b giá trị hiện tại của $a cộng với 3 (20)
$b = $b * 2;  #  cho $b giá trị của $b được nhân với 2 (40)
Chú ý rằng dòng cuối dùng biến $b hai lần: khi lấy được giá trị của nó (ở vế phải dấu =), và khi xác định xem phải đặt biểu thức tính được vào đâu (ở vế trái của dấu =). Điều này là hợp lệ, an toàn và trong thực tế, khá thông dụng. Trong thực tế, nó thông dụng đến mức chúng ta sẽ thấy trong vài phút đây là ta có thể viết điều này bằng việc dùng cách viết tắt qui ước.
Bạn có thể đã chú ý rằng các biến vô hướng bao giờ cũng được tham khảo bằng dấu $ đứng trước. Trong lớp vỏ, bạn dùng $ để lấy một giá trị, nhưng để $ đứng một mình để gán một giá trị mới. Trong awk hay C, bạn để cho $ riêng hoàn toàn. Nếu bạn cứ phải viết đi viết lại các biến rất nhiều thì bạn sẽ thấy mình ngẫu nhiên bị gõ sai. Thường hay bị vậy. (Giải pháp của tôi là chấm dứt việc viết chương trình vỏ, awk và C, nhưng điều đó lại có thể không có tác dụng cho bạn.)
Việc gán vô hướng có thể được dùng như một giá trị cũng như một phép toán, như trong C. Nói cách khác, $a = 3 có một giá trị, cũng như $a+3 có một giá trị. Giá trị chính là số được gán, cho nên giá trị của $a = 3 là 3. Mặc dầu điều này dường như có vẻ kì lạ lúc thoáng nhìn, việc dùng một phép gán như một giá trị lại có ích nếu bạn muốn gán một giá trị trung gian trong một biểu thức cho một biến, hay nếu bạn muốn đơn giản sao cùng một giá trị cho một hay nhiều biến. Chẳng hạn:
$b = 4 + ($a = 3); #  gán 3 cho $a, rồi cộng kết quả đó với 4 đặt vào $b, được 7
$d = ($c = 5); # sao 5 vào $c, và rồi sao vào $d
$d = $c = 5; #  cũng điều ấy nhưng không có dấu ngoặc
Thí dụ cuối làm việc tốt vì phép gán có tính kết hợp bên phải.

Toán tử gán hai ngôi
Các biểu thức như $a = $a + 5 (trong đó cùng một biến lại xuất hiện ở cả hai vế của phép gán) thường xuất hiện đến mức Perl (giống như C) có cách viết tắt cho phép toán làm thay đổi biến - toán tử gán hai ngôi. Gần như tất cả các toán tử hai ngôi tính một giá trị đều có dạng phép gán hai ngôi tương ứng với dấu bằng có bổ sung thêm phần tử. Chẳng hạn, hai dòng sau đây là tương đương:
$a = $a + 5 ; #  không có toán tử gán hai ngôi
$a += 5 ; #  có toán tử gán hai ngôi
Và tương tự như thế:
$b = $b * 3;
$b *= 3;
Trong từng trường hợp, toán tử này làm cho giá trị hiện tại của biến được thay đổi theo một cách nào đó, thay vì đơn giản ghi đè lên giá trị này bằng kết quả của một biểu thức mới nào đó.
Toán tử gán thông dụng khác là toán tử ghép nối xâu:
$str = $str . “ ”;  #  thêm dấucách vào $str
$str .= “ ”;  # cũng điều ấy với toán tử gán
Gần như tất cả các toán tử hai ngôi đều hợp lệ theo cách này. Chẳng hạn, toán tử nâng lên luỹ thừa của sẽ được viết là **=. Cho nên, $a **= 3 có nghĩa là “nâng một số trong $a lên luỹ thừa ba, rồi đặt kết quả trở lại $a”.
Giống như toán tử gán đơn, các toán tử này cũng có một giá trị : giá trị mới của biến. Chẳng hạn:
$a = 3;
$b = ($a += 4);  #  $a và $b cả hai bây giờ đều là 7
Nhưng không may là trật tự tính toán của các toán hạng của toán tử hai ngôi lại không được xác định, cho nên một số biểu thức không thể nào được xác định hoàn toàn:
$a = 3;
$b = ($a += 2) * ($a -= 2); # Chương trình tồi: $b có thể là 15 hay 3
Nếu toán hạng bên phải của phép nhân được tính đầu tiên thì kết quả sẽ là 3 lần 1, hay 3. Tuy nhiên, nếu toán hạng bên trái được tính trước toán hạng bên phải, thì nó là 5 lần 3, hay 15. Bạn chớ có làm điều này, chừng nào bạn còn chưa vào Cuộc tranh luận Perl rối rắm.

Tự tăng và tự giảm
Dừng cũng đã đủ dễ dàng để thêm một vào $a bằng việc nói $a += 1. Perl còn đi xa hơn và thậm chí lại còn làm ngắn hơn cho điều này nữa. Toán tử ++ (được gọi là toán tử tự tăng) cộng thêm một vào toán hạng của nó, và cho lại giá trị đã được tăng, giống như:
$a += 1 ; # có toán tử gán
++$a; #  với tự tăng tiền tố
$d = 17;
$e = ++$d;  #  $e và $d bây giờ đều là 18
Tại đây, toán tử ++ được dùng như toán tử tiền tố - tức là, toán tử xuất hiện ở bên trái toán hạng của nó. Phép tự tăng cũng có thể được dùng trong dạng hậu tố (nằm ở bên phải toán hạng của nó). Trong trường hợp này, kết quả của biểu thức này là giá trị của biến trước khi biến được tăng lên. Chẳng hạn,
$c = 17;
$d = $c++;  #  $d là 17, nhưng $c bây giờ là 18
Vì giá trị của toán hạng thay đổi nên toán hạng này phải là một biến vô hướng, không phải là biểu thức. Bạn không thể nói ++16 để có được 17, mà cũng không thể nói ++($a+$b) là cách nào đó để có được giá trị lớn hơn tổng của $a và $b một đơn vị.
Toán tử tự giảm (--) cũng tương tự như toán tử tự tăng, nhưng trừ đi một thay vì cộng với một. Giống như toán tử tự tăng, toán tử tự giảm cũng có dạng tiền tố và hậu tố. Chẳng hạn:
$x = 12;
--$x ;   #  $x bây giờ là 11
$y = $x-- ; #  $y là 11, còn $x bây giờ là 10
Không giống C, các toán tử tự tăng và tự giảm làm việc trên số dấu phẩy động. Cho nên việc tăng một biến với giá trị 4.2 sẽ cho 5.2 như dự kiến.

Toán tử chop()
Một toán tử có ích khác là chop(). Toán tử tiền tố này nhận một đối bên trong các dấu ngoặc của nó - tên của một biến vô hướng - và bỏ đi kí tự cuối cùng từ giá trị xâu của biến đó. Chẳng hạn:
$x = “Xin chào mọi người”;
chop($x);  #  $x bây giờ là “Xin chào mọi ngườ”
Lưu ý rằng giá trị của đối bị thay đổi ở đây, do đó cần phải có một biến vô hướng, thay vì chỉ đơn giản là giá trị vô hướng. Sẽ là vô nghĩa, chẳng hạn, để viết chop(suey) để biến nó thành sue, vì không có chỗ nào để cất giữ giá trị này. Bên cạnh đó, bạn có thể chỉ viết sue cũng đủ.
Toán tử này trông giống như một lời gọi hàm, và quả thực cho lại một giá trị (mà bạn sẽ trông đợi nếu bạn quen thuộc với lời gọi hàm từ các ngôn ngữ). Giá trị được cho lại chính là kí tự đã bị loại bỏ (chữ i trong người ở trên). Điều này có nghĩa là đoạn mã sau đây có lẽ sai:
$x = chop($x); # SAI: thay thế $x bằng ksi tự cuối cùng của nó
chop($x);  #  Đúng: như trên, loại bỏ kí tự cuối
Nếu chop() được cho một xâu rỗng, thì nó chẳng làm gì cả, và chẳng cho lại gì, mà cũng không đưa ra lỗi hay than vãn gì. Phần lớn các phép toán trong Perl đều có những điều kiện nhậy cảm - nói cách khác, bạn có thể dùng chúng ngay sát cạnh (và vượt ra ngoài) mà thường không có lời phàn nàn nào. Một số người biện minh rằng đây là một trong những nhược điểm nền tảng của Perl, trong khi số còn lại trong chúng ta  thì vẫn viết ra những chương trình tức cười mà chẳng phải lo lắng gì về phần riềm bên. Bạn quyết định xem mình sẽ theo vào phía nào.

Xen lẫn vô hướng vào trong xâu
Khi một hằng kí tự xâu là được đặt trong nháy kép thì nó là chủ đề cho việc xen lẫn biến (bên cạnh việc được kiểm tra cho lối thoát sổ chéo ngược). Điều này có nghĩa là xâu này được duyệt qua để tìm các tên biến** Và cả biến mảng nữa, nhưng chúng ta vẫn còn chưa biết đến chúng chừng nào chưa tới Chương 3, biến mảng vô hướng có thể - có nghĩa là dấu đô la đi theo sau một chữ, số hay dấu gạch thấp. Khi tìm thấy một tham khảo biến thì nó được thay thế bằng giá trị hiện tại (hay bất kì xâu rỗng nào nếu biến vô hướng còn chưa được gán giá trị nào). Chẳng hạn:
$a = “fred”;
$b = “some text $a”;  #  $b bây giờ là “some text fred”
$c = “no such variable $what”; # $c là “no such variable ”
Để ngăn cản việc thay thế một biến bằng giá trị của nó, bạn phải hoặc làm thay đổi phần đó của xâu để cho nó xuất hiện trong ngoặc đơn, hoặc đặt trước dấu đô la một dấu sổ chéo ngược, mà sẽ tắt ý nghĩa đặc biệt của dấu đô la:
$fred = hi;
$barney = “a test of “.$fred;  #  hằng kí hiệu: a test of $fred
$barney2 = “a test of \$fred”;  #  cũng như vậy
Tên biến sẽ là tên biến dài nhất có thể mà tạo nên nghĩa tại phần đó của xâu. Điều này có thể là vấn đề nếu bạn muốn đặt sau ngay giá trị được thay thế với một văn bản hằng mà bắt đầu ằng một chữ, số hay dấu gạch thấp. Vì Pserl duyệt qua các tên biến nên nó sẽ xét những kí tự là các kí tự tên phụ, mà không phải là điều bạn muốn. Perl cung cấp một định biên cho tên biến theo các hệ thốngương tự như lớp vỏ. Bạn hãy đơn thuần bao tên của biến đó trong một cặp dấu ngoặc nhọn. Hay bạn có thể kết thúc phần đó của xâu và bắt đầu một phần khác của xâu bằng toán tử ghép nối:
$fred = pay; $fredday = “wrong!”;
$barney = “Its $fredday”; #  không phải payday, mà là “Its wrong!”
$barney = “Its ${fred}day”; #  bây giờ, $barney là “Its payday!”
$barney2 = “Its $fred”;  #  cách khác để làm việc đó
$barney3 = “Its “ . $fred . “day”; và một cách khác
Toán tử sổ chéo ngược chuyển hoa thường có thể được dùng để làm thay đổi chữ hoa thường được đem theo cùng việc xen lẫn biến. Chẳng hạn:
$bigfred = “\ufred”;  #  $bigfred là FRED
$fred = “fred”;  $bigfred = “\Ufred”;  # cùng điều đó
$capfred = “\u$fred”;  #  $capfred  là “Fred”
$barney = “\LBARNEY”;  #  $barney bây giờ là “barney”
$capbarney = “\u\LBARNEY”;  #capbarney bây giờ là “Barney”
$bigbarney = “BARNEY”; $capbarney = “\u\L$bigbarney”; thế
Như bạn có thể thấy, các toán tử dịch chuyển hoa thường được ghi nhớ bên trong xâu chừng nào chúng còn chưa được dùng tới, cho nên ngay kí tự đầu tiên của BARNEY không tuân theo \u, nó vẫn còn là chữ hoa vì \u.
Thuật ngữ xen lẫn biến thường được dùng lẫn với xen lẫn nháy kép, vì các xâu có nháy kép là chủ đề cho việc xen lẫn biến.
xem như một vô hướng
Tại điểm này, nếu bạn là một người chuyên nghiệp lập trình thì bạn có thể tự hỏi làm sao lấy được một giá trị vào trong chương trình Perl. Sau đây là cách đơn giản nhất. Mỗi lần bạn dùng ở chỗ đang trông đợi một giá trị vô hướng, thì Perl sẽ đọc toàn bộ dòng văn bản tiếp từ lối vào chuẩn (cho tới dấu dòng mới đầu tiên), và dùng xâu đó như giá trị cho . Đầu vào chuẩn có thể mang nhiều nghĩa, nhưng chừng nào bạn còn chưa làm điều gì đó kì lạ, thì nó vẫn còn mang nghĩa là thiết bị cuối của người dùng, người đã gọi chương trình của bạn (có thể là bạn). Nếu không có gì chờ đợi để đọc cả (trường hợp điển hình, chừng nào bạn còn chưa gõ xong toàn bộ dòng), thì chương trình Perl sẽ dừng và đợi cho bạn đưa vào một số kí tự theo sau bằng một dấu dòng mới (xuống dòng).
Giá trị xâu của về điển hình có một dấu dòng mới ở cuối của nó. Thông thường nhất là bạn muốn gỡ bỏ cái dấu dòng mới đó đi (có sự khác biệt lớn giữa hello và hello\n). Đây là chỗ mà anh bạn chúng ta, toán tử chop(), tới cứu giúp. Một dãy cái vào điển hình đưa tới một cái gì đó tựa như thế này:
$a = ; #  nhận văn bản
chop($a); # gỡ bỏ dấu dòng mới khó chịu
Cách viết tắt thông dụng cho hai dòng này là:
chop($a = ) ;
Phép gán bên trong các dấu ngoặc tròn tiếp tục là một tham khảo tới $a, thậm chí sau khi nó đã được trao cho một giá trị với toán tử . Vậy, toán tử chop() làm việc trên $a. (Điều này là đúng nói chung đối với toán tử gán - một biểu thức gán có thể được dùng bất kì khi nào một biến là cần tới, và những hành động tham khảo tới biến đó ở bên trái của dấu bằng.)

Đưa ra bằng print()
Vậy ta thu được mọi thứ với . Ta làm sao đưa ra mọi thứ đây? Bằng toán tử print() đấy. Toán tử tiền tố này nhận một giá trị vô hướng bên trong các dấu ngoặc của nó và đưa ra mà không cần bất kì sự trang điểm nào lên lối ra chuẩn. Một lần nữa, chừng nào bạn còn chưa làm điều gì kì lạ, thì lối ra này vẫn cứ là thiết bị cuối của bạn. Chẳng hạn:
print (“Xin chào mọi người\n”);  #  nói chào mọi người, tiếp là dấu dòng mới
print “Xin chào mọi người\n”; # cũng cùng điều đó
Lưu ý rằng thí dụ thứ hai chỉ ra dạng của print() không có dấu ngoặc. Trong thực tế, nhiều toán tử trông như các hàm cũng có dạng cú pháp làm việc không cần dấu ngoặc. Dù có dùng hay không, dấu ngoặc cũng gần như là vấn đề về kiểu cách và sự nhanh nhẩu trong cách gõ, mặc dầu có vài trường hợp bạ nsẽ cần các dấu ngoặc để loại bỏ bớt sự mập mờ.
Chúng ta sẽ thấy rằng bạn thực tế có thể cho print một danh sách các giá trị, trong mục “Dùng print để đưa ra thông thường” ở Chương 6, Cơ sở về vào/ra, nhưng chúng ta  vẫn còn chưa nói về danh sách, cho nên chúng ta sẽ hoãn nó về sau.

Giá trị undef
Điều gì sẽ xảy ra nếu bạn dùng một biến vô hướng trước khi bạn cho nó một giá trị? Chẳng có gì nghiêm trọng cả, và chẳng có gì dứt khoát sẽ gây định mệnh cả. Các biến đều có giá trị undef trước khi chúng được gán lần đầu tiên. Giá trị này trông như số không khi được dùng như một số, hay xâu rỗng chiều dài không nếu được dùng như một xâu.
Nhiều toán tử cho lại undef khi các đối vượt ra ngoài phạm vi và thành vô nghĩa. Nếu bạn không làm điều gì đặc biệt thì bạn sẽ nhận được không hay xâu không mà không có hậu quả gì lớn. Trong thực hành, điều này gần nhưu không gây ra vấn đề gì.
Một toán tử mà chúng ta đã thấy có cho lại undef trong hoàn cảnh nào đó là toán tử . Thông thường toán tử này cho lại một xâu của dòng tiếp vừa được đọc, tuy nhiên (như khi bạn gõ control-D tại thiết bị cuối, hay khi một tệp không còn dữ liệu nữa), thì toán tử này cho lại undef như một giá trị. Chúng ta sẽ thấy trong chương 6 cách kiểm tả điều này và chọn hành động đặc biệt khi không còn dữ liệu nào có sẵn để đọc nữa.

Bài tập
Xem Phụ lục A về lời giải.
1. Hãy viết một chương trình tính chu vi đường tròn với bán kính 12.5. Chu vi bằng 2 lần bán kính, hay khoảng 2 lần 3.141592654.
2. Hãy sửa đổi chương trình này từ bài tập trước để nhắc việc nhận bán kính từ người chạy chương trình.
3. Hãy viết một chương trình nhắc và đọc vào hai số, rồi in ra kếtquả của việc nhân hai số đó.
4. Hãy viết một chương trình đọc một xâu và một số rồi in ra xâu số lần được chỉ ra bởi số các dòng tách biệt. (Hướng dẫn: hãy dùng toán tử “x”.)

0 nhận xét: