Mặc dầu bạn có thể nghĩ về số và xâu như những vật rất khác nhau, nhưng Perl dùng chúng gần như là giống nhau, cho nên c húng ta sẽ nghiên c ứu c ả hai.. Một giá trị vô hướng c ó thể đượ
Trang 1Diễn đàn tin học | Tutorial Room
Learning Perl - Chương 2: Dữ liệu vô hướng
1 Dữ liệu vô hướng là gì?
2 Số
3 Xâu
4 Toán tử
5 Biến vô hướng
6 Các phép toán trên biến vô hướng
7 <STDIN> xem như một vô hướng
8 Đưa ra bằng print()
9 Giá trị undef
10 Bài tập
2.1 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 như 4
hay 3.25e20) hay một xâu c ác kí tự (giống Xin c hà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, nhưng Perl dùng chúng gần như là giống nhau, cho nên c húng ta sẽ nghiên c ứu c ả hai
Một giá trị vô hướng c ó thể được tác động bởi các toán tử (giống như phép c ộng hay ghép), và kết quả trả về nói chung là 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 biến vô hướng c ó thể được đọc từ tệp và thiết bị, và c ó thể được ghi thiết bị xuất
2.2 Số
Mặc dầu kiểu vô vô hướng thì hoặc là một số hay một xâu, nhưng c ũng vẫn c ó íc h khi ta nhìn vào c ác
số và xâu tách biệt nhau trong một c hốc lát Ta sẽ xét số trước rồi đến xâu
2.2.1 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ấu chấm thập phân, như 3.14 hay 1.35*1025) Nhưng bên trong, Perl chỉ tính với c ác giá trị dấu phẩy động độ c hí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 c hươ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 c huyể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 ó phép tính nào như vậy đâu
2.2.2 Hằng kí hiệu động
Hằng kí hiệu là một c ác h để 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ã c hương trình gốc c ủa c hương trình bạn như cái vào cho trình biên dịc h 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 c hấp nhận tập hợp đầy đủ c ác hằng kí hiệu dấu phẩy động c ó sẵn c ho người lập trình C Số có hay không có dấu c hấm thập phân đều được phép (kể c ả tiền tố cộng hay trừ tuỳ c họn), c ũng như phần chỉ số mũ phụ thêm (kí pháp luỹ thừa) với c ác h viết E Chẳng hạn:
Trang 2-1.2E-23 # tương tự như số ở trên: -1,2 x 10-23
2.2.3 Hằng kí hiệu nguyên
Các hằng kí hiện nguyên c ũng được ghi trực tiếp, ví dụ:
12
15
-2004
3485
Bạn đừng bắt đầu một số bằng 0 (zero), vì Perl hỗ trợ c ho hằng kí hiệu hệ c ơ số 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 Các c hữ số hệ mười sáu từ A đến F (trong cả hai kiểu c hữ 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 = 255 trong hệ thập phân
2.3 Xâu
Xâu là một dãy c ác kí tự (như Xin c hào) Mỗi kí tự đều là một giá trị 8-bit trong toàn bộ tập 256 kí tự (không có gì đặc biệt về kí tự NULL như trong C)
Xâu ngắn nhất c ó thể được là xâu rỗng-không c ó kí tự nào Xâu dài nhất thì chiếm trọn bộ nhớ máy tính (mặc dầu bạn sẽ c hẳ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" mà Perl c ung c ấp cho bạn Các xâu điển hình là c ác dẫy in được gồm các chữ, 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 (c hẳng hạn, bạn c ó thể 'vá lỗi' UNIX bằng việc đọc nó vào trong xâu Perl, tiến hành thay đổi, và ghi lại kết quả)
Giống như số, xâu c ó thể biểu diễn hằng kí hiệu (các h thức bạn biểu diễn xâu trong c hương trình Perl)
Các xâu hằng kí hiệu có theo hai hướng: xâu nháy đơn và xâu nháy kép.
2.3.1 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 - c húng c hỉ 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 xuống dòng, 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 ngoại 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ổ c héo ngược Và để lấy được dấu sổ c hé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ổ c héo ngược nữa Ví dụ:
'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 rỗng (không c ó kí tự)
"hello\n' #hello theo sau là sổ c héo ngược và n
'hello
Chú ý rằng \n bên trong môt xâu c ó nháy đơn thì không được hiểu là dòng mới, nhưng nếu là hai kí tự
sổ c héo ngược thì khác (c hỉ khi sổ chéo ngược đi theo sau bởi một sổ c héo ngược khác hay một dấu nháy đơn thì mới mang nghĩa đặc biệt)
2.3.2 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ổ c hé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:
Trang 3"hello world\n" # hello world, và dấu xuống dòng
"new \177" # new, dấu c ác h và kí tự xoá (177 hệ tám)
"coke\tsprite" # c oke, 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ổ c héo) Danh sác h đầy đủ c ủa các lối thoát xâu nháy kép được c ho trong Bảng 2- 1
Bảng 2-1 Dấu sổ chéo ngược trong xâu nháy kép
\n xuống dòng mới
\r về đầu dòng
\t ký tự tab
\f báo hết trang
\b xoá lui 1 ký tự
\a phát 1 tiếng "bíp"
\e esc ape
\007 ký tự ASCII ở hệ tám (007=bíp)
\0x7f ký tự ASCII ở hệ mười sáu (7f=delete)
\cC ký tự điều khiển (ở đây là Ctrl-C)
\\ dấu sổ chéo ngược
\" dấu nháy kép
\l ký tự tiếp theo sẽ c huyển thành chữ thường
\L tất cả các ký tự tiếp theo cho tới \E sẽ thành chữ thường
\u ký tự tiếp theo sẽ c huyển thành chữ hoa
\U tất cả các ký tự tiếp theo cho tới \E sẽ thành 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à ở c hỗ c húng c ho 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 c hú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 phần mở đầu trên), c ho nên tôi sẽ quay lại vấn đề này sau
2.4 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 nói c hung đề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 c ung 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 c hi tiết trong mục "Chuyển đổi giữa số và xâu" dưới đây.
2.4.1 Toán tử cho số
Perl c ung c ấp các toán tử c ộng, trừ, nhân, c hia điển hình thông thường Chẳng hạn:
5.1 - 2.4 # 5.1 trừ 2.4, = 2.7
3 * 12 # 3 lần 12, = 36
14 / 2 # 14 chia cho 2, = 7
10.2 / 0.3 # 10.2 c hia c ho 0.3, = 34
Bên c ạnh đó, Perl c ung c ấp toán tử lũy thừa kiểu FORTRAN, mà nhiều người đã từng mong mỏi c ho Pasc al và C Toán tử này được biểu diễn bằng hai dấu sao, như 2**3 = 23 = 8 (nếu kết quả không thể khớp trong số dấu phẩy động độ c hí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' - fatal error)
Trang 4Perl c ũng hỗ trợ c ho toán tử lấy đồng dư mô-đun như trong C Giá trị của biểu thức 10 % 3 là số dư khi lấy 10 chia c ho 3, c hính là 1 Cả hai giá trị trước khi tính toán đều được đưa về giá trị nguyên, c ho 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ẽ c ho lại một giá trị đúng (True) hay sai (False) Chẳng hạn, 3 > 2 trả về True vì 3 lớn hơn 2, trong khi 5 != 5 trả về False 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ị c ho lại giống như c húng ở trong C - 1 là True, c òn 0 là False (c ác toán tử này sẽ được nói lại trong Bảng 2-2)
2.4.2 Toán tử xâu
Các giá trị xâu có thể được ghép với toán tử c hấm (.) (đó là dấu c hấ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 Nhưng kết quả trả về là một xâu ghép (theo thứ tự) c ủa 2 xâu thành phần, vậy là c ó sẵn c ho tính toán thêm hay được c ất giữ trong một biến:
"hello" "world" # tương tự như "helloworld"
'hello wordl' "\n" # hệt như "hello world\n"
"jerry" " " "tom" # hệt như "jerry tom"
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 là bạn đơn thuần c hỉ việc đặt hai xâu gần nhau
Một tập c ác toán tử c ho 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 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ác h thông
thường Tập đầy đủ c ác toán tử so sánh (c ho 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
Bạn c ó thể tự hỏi tại sao lại có c ác toán tử phân tác h c ho 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 c hỉ 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:
"jerry" x 3 # là "jerryjerryjerry"
"tom" x (4+1) # là "tom" x 5 hay "tomtomtomtomtom"
(3+2) x 4 # là 5 x 4, hay thực sự là "5" x 4, là "5555"
Nhưng toán tử lặp lại xâu c ần một xâu c ho toán hạng bên trái, c ho nên số 5 được c huyển thành xâu
"5" (dùng c ác qui tắc sẽ được mô tả c hi 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, c ho 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ì ta sẽ làm năm bản sao của xâu 4, c ho 44444 Điều này c hỉ 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ị c hặt đi để c ho 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 (c hiều dài không)
Trang 52.4.3 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 ác h 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ạ trong toán) thì ta được 2+12, hay 14 Perl c họn định nghĩa toán học thông thường, thực hiện nhân trước Bởi điều này, ta nói nhân c ó số ưu tiên c ao hơn c ộng
Bạn c ó thể phá đi trật tự theo số ưu tiên bằng việc dùng dấu ngoặc 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 c hẳ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ách đú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 (c hú ý rằng một số các toán tử c òn chưa được mô tả) Với những toán tử c ũng c ó trong C, thì những toán tử đó c ó c ùng số thứ tự ưu tiên như c húng c ó trong C (mà tôi c hẳng bao giờ c ó thể 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)
Trái các toán tử về "danh sác h" (mảng) Trái > (gọi hàm)
- (không xét) ++ (tăng 1) hoặc (giảm 1) Phải ** (luỹ thừa)
Phải ! ~ \ + - (phủ định lôgic, phủ định bit, tham khảo biến
(như pointer trong C), số dương, số âm) Trái =~ !~ (sánh, không sánh)
Trái * / % x (nhân, c hia, đồng dư, lặp c huỗi) Trái + - (cộng, trừ, ghép xâu)
Trái << >> (dịc h c huyển bit)
- các toán tử 1 toán hạng (như chomp)
- < > <= >= lt gt le ge
- == != <=> eq ne cmp
Trái & (phép lôgíc 'and' theo bit) Trái | ^ (phép lôgíc 'or', 'xor' theo bit) Trái && (phép lôgíc 'and')
Left || (phép lôgíc 'or')
- (toán tử phạm vi), (cấu tử danh sác h) Phải ?: (if- then-else, như trong C)
Phải = += -+ += (c ác phép gán) Trái , => (ngăn c ách bằng , và bằng =>)
- các toán tử về danh sác h (array) Phải not (phép lôgíc 'not')
Trái and (phép lôgíc 'and') Trái or xor (phép lôgíc 'or', 'xor') Trong sơ đồ này, bất kì toán tử đã c ho 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ó 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