Hôm nay ta sẽ tìm hiểu Python bằng một ví dụ minh họa nho nhỏ về mã hóa dịch ngược. Cụ thể là sau khi nhập vào một câu, nó sẽ đảo thứ tự chữ cái trong câu ban đầu hệt như bạn cầm tờ giấy viết câu đó và để nó trước 1 tấm gương rồi đọc vậy.
Các hàm ta sẽ sử dụng trong đây bao gồm: input(), len() và vòng lặp while. Còn nhiều khái niệm nữa mà trong quá trình viết tôi sẽ dần dần giải thích sau.
Môi trường để minh họa các bài viết về Python, tôi sử dụng máy ảo Ubuntu và Python 3. Chính xác, Python 3 nhé.
The Revese Cipher
Dịch ngược một chuỗi ký tự có nghĩa là đảo ngược cả cách viết chữ đó trên giấy. Thật thú vị nếu bạn viết được chữ ‘g’ ngược trên giấy một cách tròn trịa. Nhưng máy tính với vài dòng code đơn giản có thể làm được điều đó. Lấy ví dụ, nếu tôi gõ tên của mình vào màn hình chạy code: “Thuong” thì kết quả sau khi nhấn Enter tôi sẽ thu được là “gnouhT“.
Một challenge nho nhỏ, bạn thử tìm cách dịch ngược nó bằng mắt xem rốt cuộc câu dưới đây là gì:
Source code of the Reverse Cipher Program
Đây là code của tôi, tham khảo rồi viết lại từ cuốn sách Hacking Secret Ciphers With Python.
print(‘Input your message to encrypt: ‘)
message = input()
encrypted = ”
i = len(message) – 1
while i >= 0:
encrypted = encrypted + message[i]
i = i – 1
print(‘Your secret text: ‘ + encrypted)
Trong sách cũng nói rõ mọi người có thể tùy biến lại code, vì nó được public dưới giấy phép BSD Licensed.
How the Program Works
Tôi sẽ xét từng dòng trong code để giải thích rõ. Thật ra tôi cũng lười lắm nhưng trót bắt tay vào viết rồi, thôi thì viết cho chỉnh chu.
print(‘Input your message to encrypt: ‘)
Dòng này thực sự không có gì đặc biệt. Nó chỉ có chức năng in ra màn hình câu yêu cầu người dùng nhập vào chuỗi cần mã hóa.
Cụ thể, thông báo sẽ xuất hiện trên màn hình sẽ là: “Input your message to encrypt:”.
message = input()
Ở đây, tôi dùng biến có tên ‘message’ để lưu trữ giá trị chuỗi mà người dùng nhập vào. Muốn lấy được nội dung mà người dùng nhập vào, cách tôi dùng là đơn giản dùng hàm input().
Có một lưu ý quan trọng ở đây. Nếu bạn dùng Python 2, chắc chắn hàm input() ở đây sẽ báo lỗi nếu người dùng nhập vào 2 từ trở lên. Còn với Python 3 thì không. Đó chính là lý do vì sao, ngay từ đầu tôi khuyến cáo sử dụng Python 3 là vậy.
encrypted = ‘ ‘
Biến ‘encrypted’ này có chức năng lưu trữ chuỗi dịch ngược thành quả cần lấy. Để sử dụng được nó, ta phải khai báo đó là một chuỗi trắng bằng cách dùng hai dấy nháy đơn. Lưu ý là chuỗi trắng (blank string) phải là sử dụng hai dấu nháy đơn, không phải hai dấu nháy đôi.
i = len(message) – 1
Ở đây ta thấy sử dụng một biến ‘i’ có sự tính toán trong đó chứ không set cứng một giá trị hay là nhận giá trị người dùng nhập vào. Quan sát, ta thấy được trong đây có sử dụng hàm len() của Python.
Hàm len() để xác định độ dài của chuỗi. Hết! Chỉ đơn giản vậy thôi. Khi sử dụng hàm len() cụ thể với một chuỗi, nó sẽ đếm xem chuỗi đó dài bao nhiêu ký tự. Ví dụ, tôi dùng hàm len(‘Vo Tinh Thuong’) thì kết quả thu được trên màn hình sẽ là số 14. Nó đếm cả các khoảng trắng giữa các từ với nhau trong chuỗi luôn.
Vậy tại sao lại có trừ bớt đi 1? Ta sẽ tìm hiểu tiếp theo ngay sau đây, bởi giải thích lúc này sẽ hoàn toàn khó hiểu.
while i >= 0:
Hàm while trong Python được sử dụng. Cấu trúc hàm while bao gầm 4 thành phần:
- The while keyword: từ khóa while khai báo để nhận biết sử dụng vòng lặp while.
- A condition: Điều kiện lặp. Giá trị ở chỗ này trả về phải là kiểu Boolean, tức là hoặc True hoặc False. Không có tính toán gì ở đây cả.
- A colon: dấu hai chấm biểu đạt ý kết thúc điều kiện lặp và bắt đầu thực hiện công việc của vòng lặp.
- A block of code: Khối các công việc sẽ được thực hiện theo điều kiện True của vòng lặp này. Có thể có nhiều việc, hoặc chỉ 1 việc tùy vào sự lập trình theo nhu cầu người tạo ra.
encrypted = encrypted + message[i]
i = i – 1
Đây, tới lúc này bắt đầu (khối) công việc. Nếu vòng lặp while ở trên thỏa điều kiện, thì công việc này mới được thực hiện. Hiểu đơn giản thì cách đọc ý nghĩa vòng lặp ở trên như sau: “Trong khi điều kiện i >= 0 còn đúng (thỏa điều kiện) thì sẽ hai chấm và săn tay áo lên lao vào mớ công việc (a block of code) bên dưới đây.
message[i] tức là lấy ra ký tự trong chuỗi ở vị trí thứ i. i là số đếm có được từ bước tính toán ở trên – cũng chính là index của ký tự trong chuỗi. Và nhớ lại bài index Python ở lần trước, ta nhớ ra, trong hầu hết các ngôn ngữ, việc đánh index luôn bắt đầu bằng số 0 cho ký tự đầu tiên. Có 6 ký tự thì là 0,1,2,3,4,5.
Nhưng với hàm len() để xác định độ dài của chuỗi, thì nó đếm theo kiểu đếm của con người, tức là xuất phát từ 1. Vậy nếu có 6 ký tự thì sẽ có kết quả là 1,2,3,4,5,6 =>6 ký tự.
Chính do sự chênh lệch đó mà i ta cần dùng sẽ chênh lệch nhau giữa 2 bước, dẫn đến việc chạy vòng lặp và lấy ra ký tự không đúng. Thế nên mới phải trừ bớt đi 1 số để phù hợp với việc lấy index xuất ra ký tự trong khối công việc trong vòng lặp while.
Diễn giải có vẻ rối quá phải không? =))))))
Nếu từng học qua ngôn ngữ lập trình nào trước đó rồi, thì chỗ này hoàn toàn có thể hiểu nhanh chóng chứ không cần phải lạc vào ma trận chữ nghĩa của tôi như vầy.
Đôi khi ngôn ngữ cũng bất lực trước một sự việc nào đó trong việc miêu tả lại. Thế mới thấy, nhà văn là người chơi chữ điêu luyện nhất. Chỉ với 26 chữ cái, người ta có thể viết ra vô số câu chữ sáng tạo, kết tụ lại thành một tác phẩm bất hủ.
Ngày xưa khi còn học phổ thông, khả năng trình bày văn chương của tôi nói không ngoa thì cực kỳ tinh xảo. Thời đó tôi không học chuyên văn nhưng có thi học sinh giỏi văn, được giải Nhì cấp huyện (không có giải Nhất).
Nếu đọc chỗ giải thích trên quá khó hiểu, bạn nên dừng lại và tìm cho mình một ly nước lọc. Nên tập uống nước lọc bình thường thay vì tu ừng ực nước lạnh nước đá. Tôi bỏ uống nước đá tính tới nay đã được 6 năm. Dĩ nhiên thỉnh thoảng đi tiệc vì tính chất môi trường cũng uống nhưng trong cuộc sống thường nhật tôi luôn uống nước lọc thường, không uống nước đá.
Tiếp tục trở lại vấn đề. Lan man kinh khủng =)))
Như vậy, i lúc đầu tính được, giả sử len(‘Thuong’) thì sẽ có kết quả là i = 6. Nhưng trừ bớt đi 1 thì sẽ là 5. i = 5 là một điều tuyệt đối đúng vào ngữ cảnh này.
Tiếp, xét i trong vòng lặp, i >= 0 là điều càng đúng. Đó gần như là một điều xác tín không gì bàn cãi, cũng như việc Trái Đất quay quanh Mặt Trời (tôi không lấy ví dụ với việc một ngày có 24 tiếng vì thời gian vốn có tính co dãn, vả lại chắc gì 1 ngày thực sự có 24 giờ).
Như vậy i đúng thỏa điều kiện, thực hiện công việc gán ký tự thứ 5 vào vị trí đầu tiên trong biến encrypted. Để lần lượt các ký tự được đưa vào lưu trữ trong biến encrypted, ta sử dụng cách encrypted = encrypted + message[i] sẽ giúp khi in ra kết quả, biến encrypted sẽ hiển thị trọn vẹn chuỗi chứ không phải từng ký tự đơn lẻ kéo dài 1 cột đứng.
i = i – 1
Đây là lúc giảm i xuống để tiếp tục đi ngược từ bên phải về bên trái chuỗi, nhằm lấy ra tất cả các ký tự ở trong ‘message’ và cho vào ‘encrypted’.
Em ngược đường, ngược nắng để yêu anh
Ngược phố tan tầm, ngược chiều gió thổi
Ngược lòng mình tìm về nông nổi
Lãng du đi vô định cánh chim trời
print(‘Your secret text: ‘ + encrypted)
Cuối cùng là xuất ra kết quả thôi chứ không có gì ghê gớm. Lưu ý sau dấu hai chấm ở dòng “Your secret text:” thì nên có một khoảng trắng để khi hiển thị ra, nội dung trong biến encrypted không bị dính liền vào câu thông báo.
Thế là bây giờ ta có thể giải được challenge ở đầu bài rồi:
osla eb traeh ruoy lliw ereht ,si erusaert ruoy erehW
Where your treasure is, there will your heart be also
VÕ TÌNH THƯƠNG
votinhthuong9@gmail.com