Base62 là gì?
Base62 là cách viết một số chỉ bằng các ký tự sống sót khi được dán ở bất kỳ đâu: mười chữ số, 26 chữ cái hoa và 26 chữ cái thường. Không có dấu câu, không có khoảng trắng, không có ký tự đệm, không có gì cần thoát trước khi đưa vào URL, tên tệp, cookie hay khóa cơ sở dữ liệu. Mười cộng 26 cộng 26 bằng 62, và đó là nguồn gốc của cái tên.
Phiên bản 30 giây: số 12345 được viết là 3D7, và 1234567890 được viết là 1LY7VK. Đi ngược lại là cùng một phép toán theo chiều ngược, và cần đúng bảng chữ cái đã tạo ra mã — một bảng khác sẽ biến sáu ký tự đó thành một số khác, mà không có thông báo lỗi nào.
Trang này thực hiện hai nhiệm vụ liên quan, và sự khác biệt giữa chúng quan trọng hơn bất kỳ điều gì khác trên trang:
- Chế độ số nguyên coi đầu vào là một số. Một ID thập phân như
1234567890 thành 1LY7VK, và các số 0 đứng đầu của đầu vào không thuộc giá trị, nên chúng không được trả lại. - Chế độ byte coi đầu vào là một chuỗi byte. Các byte được đọc như một số big-endian khổng lồ rồi chia cho 62 — cùng phép tính nhưng trên một đại lượng khác. Ở đây, số byte 0 đứng đầu vẫn được giữ lại, mỗi byte 0 thành một ký tự 0.
62 đến từ đâu, và nó tốn gì
62 không phải lũy thừa của 2, và chính điều đơn lẻ đó định hình mọi thứ còn lại. Các mã hóa quen thuộc được xây dựng bằng cách cắt đầu vào thành các nhóm bit cố định: 4 bit in thành một ký tự thập lục phân, 6 bit thành một ký tự Base64, 5 bit thành một ký tự Base32. Base62 không làm được như vậy, vì không có số bit nguyên nào vừa khít một ký tự có 62 giá trị — 5 bit chỉ đặt tên được 32 giá trị, 6 bit đặt tên được 64. Vì vậy Base62 đi qua phép tính: đọc toàn bộ đầu vào như một số nguyên, rồi in nó theo cơ số 62.
Khi đó một ký tự mang log2(62) = 5,954 bit, rất gần với 6 của Base64, và ở chế độ thập phân một ký tự thay thế log62(10) = 1,792 chữ số thập phân. Vài hệ quả nên biết trước khi chọn độ dài:
| Độ dài mã | Các giá trị đặt tên được | Trong thực tế |
| 4 ký tự | 624 = 14.776.336 | Đủ cho một bộ đếm dưới tám chữ số, và vừa với khoảng không gian bằng một số điện thoại. |
| 6 ký tự | 626 = 56.800.235.584 | Hình dạng thường gặp của một mã ID. Một ID thập phân mười chữ số vừa với sáu ký tự. |
| 7 ký tự | 627 = 3.521.614.606.208 | Vượt phạm vi của bộ đếm 32 bit hai bậc độ lớn, trong độ rộng của một slug liên kết ngắn. |
| 11 ký tự | 6211 = 52.036.560.683.837.093.888 | Lớn hơn 264 = 18.446.744.073.709.551.616, nên một số 64 bit đầy đủ vừa trong mười một ký tự. |
Nhìn theo chiều ngược lại, 1.000 chữ số thập phân cần khoảng 558 ký tự, và 4.096 chữ số thập phân cần 2.285 ký tự. Tiết kiệm là có thật nhưng có giới hạn: Base62 làm ngắn một số thập phân khoảng 44%, và nó không bao giờ vượt các mã hóa có thể in được dày đặc nhất, vì 5,954 bit mỗi ký tự đơn giản là ít hơn 6,4 hay 6,5.
Chế độ số nguyên: điều gì xảy ra với số 0 đứng đầu
Một số nguyên có một dạng viết chuẩn duy nhất và nó bắt đầu bằng ký tự số 0 của bảng chữ cái, tức là 0 trong hai thứ tự chữ số đứng trước và A trong thứ tự chữ cái đứng trước. Mọi thứ nằm bên trái của ký tự có nghĩa đầu tiên là phần đệm, và phần đệm không thuộc giá trị: 00012345 và 12345 đều thành 3D7. Nếu cần độ rộng cố định — ví dụ một mã bảy ký tự phải thẳng hàng trong một cột — ô Đệm kết quả đến độ rộng cố định của trang lặp các ký tự 0 cho đến khi đạt độ rộng, nên 12345 ở độ rộng 7 in thành 00003D7 trong bảng chữ số đứng trước và AAAADNH trong bảng chữ cái đứng trước. Phần đệm chỉ mang tính hình thức: các ký tự đứng đầu đó không thêm gì vào giá trị, và giải mã cả hai chuỗi đều cho lại 12345, vì 0 × 626 và 0 × 625 đều bằng không bất kể ký tự nào viết số 0.
Vì vậy giải mã một chuỗi có đệm cũng hoạt động, và trang báo cho bạn có bao nhiêu ký tự đứng đầu là ký tự 0, để sự khác biệt giữa “mã dài bảy ký tự” và “giá trị chỉ cần ba ký tự” không bao giờ là điều bí ẩn.
Chế độ byte: cùng phép tính trên một chuỗi byte
Chế độ byte đọc các byte đầu vào như một số nguyên big-endian duy nhất — toàn bộ chuỗi byte được coi là một số, bất kể dài bao nhiêu — rồi in số đó theo cơ số 62. Vì một byte chứa 8 bit còn một ký tự biểu thị 5,954 bit, chế độ byte không phải là nén: nó cần khoảng 134% kích thước đầu vào, kém Base64 (133%) một chút. Với mẫu 92 byte dùng trong bảng kích thước phía trên, 92 byte in thành 124 ký tự Base62, còn Base64 cũng in 124 (123 ký tự trước phần đệm =). Base62 thua Base64 về mật độ và thắng về độ an toàn của ký tự, đó là sự đánh đổi mà mọi liên kết ngắn và mã mời đều chủ động chọn.
Các byte 0 đứng đầu được bảo toàn, và điều này dễ sai theo cả hai chiều. Hai byte 0 đứng đầu theo sau là 0x01 in thành 001 trong bảng chữ số đứng trước và AAB trong bảng chữ cái đứng trước, vì các ký tự đứng đầu biểu thị số 0 và mỗi byte 0 là một ký tự. Một chuỗi byte chỉ có 0x00 in thành một ký tự 0, và một chuỗi byte chỉ có 0x01 in thành 1. Đây là chỗ duy nhất mà chế độ byte và chế độ số nguyên trông khác nhau trong khi chạy cùng một thuật toán.
Cái giá của tất cả điều này là chế độ byte kế thừa độ phức tạp bậc hai của phép tính: 1.024 byte được ước tính mất khoảng một phần ba giây và 2.048 byte mất khoảng 1,3 giây, cùng các con số mà bảng giới hạn phía trên đưa ra. Đó là lý do chế độ byte ở đây bị giới hạn ở 2.048 byte khi mã hóa và 2.048 ký tự khi giải mã — 2.048 byte in ra khoảng 2.751 ký tự, nên khoảng 1.520 byte là tải trọng lớn nhất còn sống sót qua một vòng khứ hồi trên trang này — và đó là lý do chế độ byte trên trang này là tài liệu tham khảo cho giá trị nhỏ, chứ không thay thế được Base64 hoặc Base91 cho tệp thật.
Ba bảng chữ cái, và vì sao bảng chữ cái là toàn bộ câu chuyện
Các ký tự của một bảng chữ cái là một dãy cố định, và giá trị của một ký tự là vị trí của nó trong dãy đó. Thay đổi thứ tự của dãy sẽ đổi ý nghĩa của mọi ký tự. Ba thứ tự đang được dùng rộng rãi, và đây là cùng một số được viết theo ba cách trong mỗi thứ tự đó:
| Thập phân | 0-9 rồi A-Z rồi a-z | 0-9 rồi a-z rồi A-Z | A-Z rồi a-z rồi 0-9 |
| 0 | 0 | 0 | A |
| 61 | z | Z | 9 |
| 62 | 10 | 10 | BA |
| 12.345 | 3D7 | 3d7 | DNH |
| 1.234.567.890 | 1LY7VK | 1ly7vk | BViHfU |
Đọc ba cột cuối như một bảng chữ cái thống nhất thì nó là một sơ đồ nhất quán. Đọc chúng như thể hoán đổi được thì nó sụp đổ, vì việc giải mã mù bảng chữ cái theo cách tệ nhất có thể: bất kỳ ký tự nào của đầu vào đều nằm trong cả ba bảng chữ cái, nên bảng chữ cái sai không tạo ra lỗi nào, chỉ ra một số khác.
| Một mã | Đọc như 0-9 A-Z a-z | Đọc như 0-9 a-z A-Z | Đọc như A-Z a-z 0-9 |
| 3D7 | 12.345 | 13.957 | 211.665 |
| 1LY7VK | 1.234.567.890 | 1.624.950.792 | 48.723.527.772 |
Phân biệt hoa thường là một phiên bản sắc hơn của cùng cái bẫy đó. Base62 phân biệt hoa thường trong mọi thứ tự, nên viết thường một mã sẽ âm thầm viết lại nó: 1LY7VK là 1.234.567.890 trong bảng chữ số đứng trước, còn 1ly7vk là 1.624.950.792 trong cùng bảng đó — và nó tình cờ là 1.234.567.890 trong bảng chữ số rồi chữ thường, vì thứ tự đó chính là bảng chữ số đứng trước với hai dạng hoa thường đổi chỗ. Ký tự số 0 cũng không được dùng chung: hai thứ tự chữ số đứng trước viết số 0 là 0, còn thứ tự chữ cái đứng trước viết nó là A, nên bảng đó không bắt đầu bằng chữ số.
Base62 đặt cạnh các mã hóa khác
| Mã hóa | Bit mỗi ký tự | Kích thước so với đầu vào | Ghi chú |
| Base16 (hex) | 4 | 200% | Hai ký tự cho mỗi byte, dễ đọc tuyệt đối, không cần tra bảng chữ cái. |
| Base32 | 5 | 160% | Không phân biệt hoa thường và an toàn khi đọc chính tả, là cái lãng phí nhất trong nhóm. |
| Base36 (0-9 a-z) | ~5,17 | ~155% | Chỉ có chữ số và chữ thường, nên sống sót qua một đường ống chuyển thành chữ thường. 12345 là 9ix. |
| Base58 | ~5,86 | ~137% | Được chọn cho địa chỉ chứ không phải cho mật độ: bốn ký tự dễ nhầm lẫn bị bỏ đi thay vì được sắp xếp. Xem Base32 / Base58. |
| Base62 | ~5,95 | ~134% | Mọi ký tự đều là chữ số hoặc chữ cái, nên không có gì bị thoát. Mật độ nằm giữa Base58 và Base64. |
| Base64 | 6 | 133% | Mặc định ở khắp nơi, đổi lại là +, / và =, ba ký tự buộc phải thoát. Xem Công cụ Base64. |
| Ascii85 / Base85 | 6,4 | 125% | 5 ký tự cho mỗi 4 byte, nhưng chia cho 85 và bảng chữ cái của nó cần đặt trong dấu nháy. Xem Ascii85. |
| Base91 | ~6,5 | ~123% | Dày đặc nhất trong các mã này, và đầu ra của nó là thứ kém an toàn nhất khi dán mà không thoát. Xem Base91. |
Các phần trăm là chi phí tiệm cận, đã làm tròn; số ký tự đo được cho một đầu vào 92 byte thực tế nằm trong bảng kích thước phía trên trang này. Trong chế độ số nguyên, phép so sánh chạy theo chiều ngược lại, vì đầu vào là văn bản thập phân chứ không phải byte: ở đó Base62 ngắn hơn khoảng 44% so với các chữ số mà nó thay thế, và Base36 ngắn hơn khoảng 36%, đó là lý do một mã ID thường là Base62 hoặc Base36 chứ không phải Base58.
Base62 không phải là gì
- Không phải tiêu chuẩn. Không có RFC và không có đặc tả. Không có tổ chức tiêu chuẩn nào từng định nghĩa Base62, đó là lý do bảng chữ cái không được bảo đảm và vì sao trang này in cả ba thứ tự thay vì lặng lẽ chọn một.
- Không phải mã hóa. Đó chỉ là đổi cơ số, không hơn. Ai biết bảng chữ cái đều đảo ngược được trong một lượt, và không có khóa, không có salt và không có bí mật nào cả.
- Không phải nén. Chế độ byte làm dữ liệu lớn thêm khoảng một phần ba. Chế độ số nguyên chỉ trông giống nén vì văn bản thập phân vốn là cách kém hiệu quả để viết một số.
- Không phân biệt hoa thường. Base32 có thể viết thường rồi đọc lại; Base62 thì không. Một mã đi qua hệ thống chuẩn hóa hoa thường là mã đã hỏng.
- Không tự kiểm tra. Không có tổng kiểm tra và không có ký tự kiểm tra, nên một ký tự sai vẫn cho kết quả trông hợp lệ nhưng khác giá trị. Nếu điều đó quan trọng, thứ tự Bitcoin đi kèm tổng kiểm tra — xem mục Base58Check của Base32 / Base58.
- Không có độ dài cố định. Số ký tự tăng theo giá trị, nên một bộ đếm bắt đầu từ 1 và lên tới 627 sẽ đi từ một ký tự thành tám ký tự. Hãy đệm đến độ rộng cố định khi cần một cột ổn định.
Những cái bẫy thực sự gây hại
- Bảng chữ cái giải đáp chín trên mười bí ẩn. Nếu công cụ khác cho mã khác với cùng một số, hãy so sánh hai bảng chữ cái từng ký tự trước khi nghi ngờ có lỗi. Bảng trên cho thấy cùng một giá trị trong ba bảng chữ cái, và cả ba đều đúng.
- Bảng chữ cái sai thất bại âm thầm. Không có đường báo lỗi cho trường hợp này:
3D7 giải mã thành 12.345, 13.957 hoặc 211.665 chỉ tùy theo thứ tự nào được giả định. Hãy kiểm tra ký tự đầu, vì nó có khả năng cao nhất là đệm số 0, và kiểm tra xem bảng chữ cái có chữ số hay chữ cái ở đầu. - Số 0 đứng đầu mang hai nghĩa khác nhau. Ở chế độ số nguyên
00012345 và 12345 là cùng một số và in giống nhau. Ở chế độ byte, byte 0 đứng đầu là dữ liệu, và nó in thành thêm một ký tự 0. Bỏ đi một trong các ký tự đó sẽ làm thay đổi chuỗi byte. - Chuẩn hóa hoa thường phá hủy mã. Một địa chỉ email, tên máy chủ hay đường dẫn Windows có thể bị viết thường trên đường đi. Mã Base62 không sống sót qua điều đó, và đó là lý do Base36 vẫn tồn tại.
- Đầu vào dài thì chậm, không chỉ là lớn. Phép chuyển đổi là phép tính trên toàn bộ đầu vào cùng lúc, nên tăng gấp đôi độ dài đầu vào làm thời gian tăng gấp bốn. Trang này từ chối đầu vào vượt các giới hạn đã đo thay vì treo; bảng kích thước phía trên cho các con số đo được.
- Một chuỗi Base62 không chứng minh được điều gì. Vì hầu như mọi chuỗi chữ số và chữ cái đều giải mã không phàn nàn, một slug URL tùy ý sẽ giải mã ra một số nào đó. Mã chỉ có ý nghĩa nếu hệ thống đã cấp nó cũng lưu ánh xạ.
Trả lời nhanh
“Vì sao một công cụ Base62 khác lại cho mã khác với cùng một số?”
Vì bảng chữ cái khác nhau. Base62 không có đặc tả nào để các triển khai phải tuân theo, nên các triển khai chọn một thứ tự: chữ số và chữ hoa trước, chữ số và chữ thường trước, hoặc chữ cái trước chữ số. Đổi ô chọn bảng chữ cái ở đầu trang này để thấy cả ba câu trả lời cạnh nhau.
“Base62 có an toàn trong URL không?”
Có, trong cả ba thứ tự. Tất cả 62 ký tự đều là chữ và số không cần thoát, nên không ký tự nào bị mở rộng thành bộ ba phần trăm trong chuỗi truy vấn, và không ký tự nào kết thúc một URL, một đoạn đường dẫn hay một thuộc tính HTML. Đó là toàn bộ lý do liên kết ngắn dùng Base62 chứ không phải Base64.
“Base62 hay Base64 nhỏ hơn?”
Với byte, Base64 nhỏ hơn một chút: khoảng 133% kích thước đầu vào so với khoảng 134%. Với mẫu 92 byte ở trên, hai bên bằng nhau ở 124 ký tự. Với số thập phân, Base62 làm ngắn văn bản khoảng 44%, và đó là nơi lợi ích thực tế nằm.
“Tôi có thể giải mã một chuỗi Base64 bằng trang này không?”
Không, và nó sẽ không báo rằng nó đã thất bại. Hai bảng chữ cái trùng nhau ở cả 62 ký tự, nên một chuỗi Base64 thường cũng là đầu vào “hợp lệ” ở đây và chỉ giải mã ra một số khác. Hãy dùng Base64 cho Base64.
“Một mã Base62 có độ dài tối đa không?”
Về lý thuyết thuật toán không có giới hạn. Trong thực tế trang này dừng ở 4.096 chữ số thập phân, hoặc 2.048 byte, vì phép tính đằng sau nó có độ phức tạp bậc hai và tab sẽ bị đứng với không có gì trên màn hình để giải thích vì sao. Bảng giới hạn phía trên trang liệt kê các con số đo được.
“Làm sao tôi biết kết quả trên trang này là đúng?”
Nhấn Tự kiểm tra. Nó chạy mọi mẫu được tài liệu hóa, mọi độ dài byte từ 0 đến 64 và một loạt số thập phân qua cả ba bảng chữ cái, so sánh các giá trị trả về với đầu vào, và kiểm tra lại rằng 62 ký tự của mỗi bảng đều an toàn trong URL. Nút Mẫu còn so sánh ba kết quả của nó với các giá trị được ghi trong tệp dữ liệu của trang, đã được kiểm chứng với một triển khai số nguyên lớn độc lập thứ hai được lưu trong công cụ kiểm thử của trang web này.
Tiêu chuẩn và ghi công
Ở đây không có tiêu chuẩn nào để triển khai: Base62 là một quy ước, không phải một đặc tả, và ba bảng chữ cái in ở trên là những bảng xuất hiện trong phần mềm thật. Trang này triển khai nó bằng các thư viện số nguyên lớn của chính trang web, viết bằng phép toán thuần trên mảng chữ số để không kích thước nào bị giới hạn bởi kiểu số của JavaScript.
Văn bản trang này được viết riêng cho trang web. Mọi ví dụ được làm việc trên trang đều do chính mã của trang tạo ra, rồi được kiểm chứng với một triển khai độc lập thứ hai dùng số nguyên lớn gốc, được lưu trong công cụ kiểm thử của trang web này; cùng triển khai đó đã kiểm chứng các bảng mẫu và kích thước trong tệp dữ liệu.