Bộ đếm byte

Dán văn bản và xem kích thước byte của nó trong UTF-8, UTF-16 và ASCII. Tuyệt vời để kiểm tra giới hạn cột cơ sở dữ liệu.

Kết quả

Nhập văn bản và nhấp vào Đếm byte.

Cách thức hoạt động

  1. Nhập hoặc dán văn bản: Nhập hoặc dán bất kỳ văn bản nào vào ô nhập liệu.
  2. Xem số byte: Công cụ hiển thị ngay lập tức số byte trong UTF-8, UTF-16, ASCII và các mã hóa khác cạnh nhau.
  3. Kiểm tra giới hạn: So sánh số byte với các giới hạn phổ biến (SMS: 160 ký tự, tiêu đề HTTP: 8 KB, trường cơ sở dữ liệu, v.v.) để xem nội dung của bạn có vừa không.

Tại sao nên dùng Bộ đếm byte?

Số ký tự và số byte không giống nhau. Một biểu tượng cảm xúc đơn lẻ có thể chiếm 4 byte trong UTF-8. Ký tự Trung Quốc và Ả Rập chiếm 2-3 byte mỗi ký tự. Nhiều hệ thống áp đặt giới hạn byte chứ không phải giới hạn ký tự, bao gồm trường MySQL VARCHAR, giá trị Redis, tiêu đề HTTP, tin nhắn SMS và tên đối tượng lưu trữ đám mây. Bộ đếm byte cho thấy kích thước byte thực tế của văn bản trong mỗi mã hóa để bạn có thể nằm trong giới hạn hệ thống.

Tính năng

Câu hỏi thường gặp

Tại sao số byte lớn hơn số ký tự của tôi?

Nhiều ký tự chiếm hơn 1 byte trong UTF-8. Ký tự ASCII (A-Z, 0-9, dấu câu) là 1 byte mỗi ký tự. Ký tự Latin mở rộng (chữ có dấu) là 2 byte. Ký tự Trung Quốc, Nhật Bản, Hàn Quốc và Ả Rập thường là 3 byte. Biểu tượng cảm xúc thường là 4 byte.

Hầu hết các hệ thống web dùng mã hóa gì?

UTF-8 là mã hóa chiếm ưu thế cho nội dung web, API, JSON và cơ sở dữ liệu. MySQL và PostgreSQL sử dụng UTF-8 theo mặc định. Khi kiểm tra giới hạn byte, hãy dùng cột UTF-8 trừ khi hệ thống của bạn chỉ định khác.

Tại sao tin nhắn SMS có giới hạn 160 ký tự?

SMS truyền thống sử dụng mã hóa GSM 7 bit, cho phép 160 ký tự mỗi phân đoạn. Khi bạn thêm bất kỳ ký tự không phải GSM nào (như dấu nháy thông minh, biểu tượng cảm xúc hoặc chữ cái không phải Latin), tin nhắn chuyển sang mã hóa UCS-2, giảm giới hạn xuống 70 ký tự mỗi phân đoạn.

Byte thực sự là gì?

Một byte là 8 bit, có thể chứa 256 giá trị riêng biệt. Trong văn bản, 256 giá trị đó được ánh xạ tới các ký tự thông qua một mã hóa, một quyển sách quy tắc nói rằng «trình tự byte này tương đương với ký tự này». Cùng một chuỗi byte có thể có nghĩa là văn bản hoàn toàn khác dưới các mã hóa khác nhau: byte 0xE9 là «é» trong Latin-1, phần đầu của một trình tự 3-byte trong UTF-8, hoặc một phần của đơn vị mã UTF-16. Mã hóa là toàn bộ câu chuyện.

Khi bạn lưu văn bản vào đĩa, gửi qua mạng, hoặc lưu trong cơ sở dữ liệu, cái thực sự được duy trì là byte, không phải ký tự. Số lượng ký tự bạn thấy trong trình soạn thảo văn bản được tính tại thời điểm hiển thị, sau khi byte được giải mã. Sai mã hóa ở một trong hai bên và bạn nhận được mojibake: văn bản được giải mã với mã hóa sai xuất hiện dưới dạng vô nghĩa (cổ điển é thay vì é khi byte Windows-1252 được đọc dưới dạng UTF-8).

Đếm byte là cái mà các giới hạn cột cơ sở dữ liệu, các bộ đệm tiêu đề HTTP, các tải SMS, và các khóa đối tượng lưu trữ đám mây đều đo lường, bất kể văn bản «trông như thế nào». Bộ đếm này báo cáo kích thước byte trong bốn mã hóa mà bạn có khả năng quan tâm nhất: UTF-8 (mặc định hiện đại), UTF-16 (định dạng nội bộ Windows / Java / JavaScript), ASCII (chỉ hợp lệ cho văn bản Latin tiếng Anh), và Latin-1 (dự phòng kế thừa một-byte). Số đếm ký tự bên cạnh được cung cấp để tham khảo.

UTF-8: Câu chuyện

UTF-8 đã được phác thảo bởi Ken Thompson và Rob Pike tại Bell Labs vào đêm 2 tháng 9 năm 1992, theo báo cáo trên một chiếc khăn ăn ở một quán ăn New Jersey, sau khi nhóm Plan 9 cần một mã hóa chiều dài thay đổi tương thích ASCII cho Unicode. Thiết kế mang ba thuộc tính mà hầu như không có gì khác có cùng một lúc: văn bản ASCII cũng là UTF-8 hợp lệ (1 byte mỗi ký tự, byte giống hệt nhau), mã hóa tự đồng bộ (các bit cao của bất kỳ byte nào cho bạn biết liệu nó bắt đầu một ký tự mới hay tiếp tục một ký tự hiện có), và không có sự mơ hồ về thứ tự byte. Ba thuộc tính đó cùng nhau giải thích tại sao UTF-8 đã thay thế mọi mã hóa cạnh tranh trên web.

Nó được tiêu chuẩn hóa lần đầu là RFC 2044 vào tháng 10 năm 1996, được sửa đổi là RFC 2279 vào tháng 1 năm 1998, và được thay thế bởi RFC 3629 (tháng 11 năm 2003) hiện tại, giới hạn UTF-8 tối đa 4 byte mỗi ký tự để phù hợp với trần điểm mã cuối cùng của Unicode tại U+10FFFF. W3Techs đã theo dõi việc sử dụng mã hóa trên web công cộng liên tục từ 2010; UTF-8 đã đi từ 56% các trang web vào năm 2011 đến khoảng 98% vào năm 2026. Đặc tả HTML5 yêu cầu UTF-8 cho nội dung mới; HTTP/2 và HTTP/3 gửi tiêu đề trong UTF-8 qua HPACK / QPACK; RFC 8259 yêu cầu UTF-8 cho trao đổi JSON giữa các hệ thống. Nếu bạn phải chọn một mã hóa cho mọi thứ, câu trả lời trong 15 năm qua là UTF-8 và câu trả lời cho 15 năm tới sẽ giống như vậy.

UTF-8 có chiều dài thay đổi, 1 đến 4 byte mỗi ký tự:

Phạm vi điểm mã Byte Nội dung điển hình
U+0000, U+007F1Các chữ cái ASCII, chữ số, dấu chấm câu thông thường
U+0080, U+07FF2Latin mở rộng (é, ñ), Hy Lạp, Kirin, Ả Rập, Do Thái
U+0800, U+FFFF3Hầu hết các chữ tượng hình CJK, Devanagari, Thái, Hangul, ký hiệu €
U+10000, U+10FFFF4Biểu tượng cảm xúc, CJK bổ sung, các chữ viết lịch sử

Hậu quả thực tế: văn bản tiếng Anh trong UTF-8 trung bình ~1 byte mỗi ký tự; tiếng Trung ~3 byte; một tin nhắn nhiều biểu tượng cảm xúc có thể đạt 4 byte mỗi ký tự nhìn thấy được, và các biểu tượng cảm xúc kết hợp (các trình tự ZWJ gia đình) dễ dàng đạt 20-30 byte cho cái trông giống như một ký tự duy nhất.

UTF-16 và cái bẫy thay thế

UTF-16 là mã hóa được lựa chọn cho Windows NT (1993), Java 1.0 (1996), JavaScript (1995), .NET và Mac OS X Cocoa NSString. Nó sử dụng 2 byte cho mỗi ký tự trong Basic Multilingual Plane (U+0000 – U+FFFF), và các cặp thay thế cho bất kỳ thứ gì bên ngoài: một thay thế cao (D800–DBFF) cộng với một thay thế thấp (DC00–DFFF), tổng cộng 4 byte. UTF-16 cần một dấu thứ tự byte (BOM) trên đĩa để phân biệt big-endian (UTF-16BE, FE FF) với little-endian (UTF-16LE, FF FE); Windows mặc định little-endian.

Cái bẫy: trong JavaScript, "😀".length === 2. MDN nói trực tiếp: thuộc tính length «chứa độ dài của chuỗi trong các đơn vị mã UTF-16». Đó là lý do tại sao một biểu tượng cảm xúc duy nhất như 😄 báo cáo độ dài 2 (nó sống trong mặt phẳng bổ sung và cần một cặp thay thế), và trình tự ZWJ gia đình 👨‍👩‍👧‍👦 báo cáo độ dài 11 (bốn biểu tượng cảm xúc 2-đơn-vị-mã cộng với ba zero-width joiner). Cùng một biểu tượng cảm xúc gia đình một-ký-tự được đếm là 11 trong JavaScript, 5 trong Python 3, và 1 trong Swift, tùy thuộc vào mô hình chuỗi của mỗi ngôn ngữ. Để đếm ký tự nhìn thấy được đúng trong JavaScript, hãy sử dụng Intl.Segmenter với độ chi tiết grapheme (mọi trình duyệt evergreen kể từ 2021).

ASCII, Latin-1, và sự hỗn loạn tiền-Unicode

ASCII (American Standard Code for Information Interchange) đã được tiêu chuẩn hóa thành ASA X3.4-1963, được sửa đổi thành X3.4-1968 và một lần nữa là ANSI X3.4-1986. Một mã 7-bit, 128 ký tự: 95 in được cộng với 33 điều khiển. 33 ký tự điều khiển bao gồm di sản máy điện báo như BEL, BS, CR, LF, DEL, và một vài cái còn tồn tại trong các giao thức hiện đại (NUL, TAB, LF, CR, ESC). ASCII vẫn hoạt động như một tập hợp con nghiêm ngặt của UTF-8, đó là lý do tại sao «văn bản ASCII thuần» cũng là UTF-8 hợp lệ và tại sao việc di chuyển sang UTF-8 không đau đớn cho các hệ thống chỉ-tiếng-Anh.

Latin-1 / ISO-8859-1 (1987) là một mở rộng 256 ký tự một-byte đã thêm các chữ cái có dấu Tây Âu, ký hiệu tiền tệ và dấu chấm câu thông thường. Đó là mã hóa thực tế cho nội dung web phương Tây từ 1995 cho đến khi UTF-8 thay thế nó khoảng năm 2008. Windows-1252 là tập siêu của Microsoft đối với Latin-1, thêm «dấu ngoặc kép thông minh», em-dash, và ký hiệu euro trong phạm vi điều khiển C1 (0x80-0x9F); khi các tệp CSV được gửi qua email giữa Mac và Windows, đó là nguồn của mojibake é cổ điển khi một bên đọc byte Windows-1252 dưới dạng UTF-8.

Cái bẫy «utf8» của MySQL

MySQL có một cái dằm khét tiếng về bộ ký tự kể từ phiên bản 4.1: bí danh bộ ký tự utf8 thực sự không phải UTF-8. Nó là một tập hợp con tối đa 3-byte không thể biểu diễn các ký tự trên U+FFFF, có nghĩa là nó không thể lưu trữ biểu tượng cảm xúc hoặc các ký tự mặt phẳng bổ sung. Chèn «🎉» vào cột utf8 tạo ra «?» hoặc lỗi tùy thuộc vào sql_mode. Bản sửa lỗi là utf8mb4, được thêm vào MySQL 5.5.3 (tháng 3 năm 2010); MySQL 8.0 (tháng 4 năm 2018) đã làm cho utf8mb4 là mặc định mới. Nhưng các lược đồ được tạo trước 8.0 thường vẫn mặc định phiên bản 3-byte. Nếu bạn thấy biểu tượng cảm xúc lặng lẽ biến mất khỏi đầu vào của người dùng, đây hầu như luôn là nguyên nhân. PostgreSQL không có cái bẫy tương đương, nó chấp nhận UTF-8 thật một cách bản địa.

SMS, GSM-7, và tải 160-byte

Giới hạn 160-ký tự SMS bắt nguồn từ một phép tính của Friedhelm Hillebrand vào năm 1985, một kỹ sư tại Nhóm Công Tác GSM, được cho là đã ngồi trên máy đánh chữ của mình, gõ các câu ngẫu nhiên, và đếm rằng «hầu hết các tin nhắn có thể được diễn đạt trong 160 ký tự hoặc ít hơn». 160 sau đó được suy ngược lại để vừa với tải 140-byte sử dụng một bảng chữ cái 7-bit (140 × 8 ÷ 7 = 160). Các chi tiết mã hóa được chính thức hóa trong 3GPP TS 23.038 (ban đầu là GSM 03.38), và chúng vẫn quản lý việc lập hóa đơn SMS ngày nay.

Tính bằng byte: một SMS duy nhất là 140 byte trên dây. Với GSM-7 đó là 160 ký tự; với UCS-2 (mã hóa chiều rộng cố định 2-byte được sử dụng cho bất kỳ thứ gì bên ngoài bảng chữ cái GSM-7) là 70. Các tin nhắn nhiều phần mất 7 ký tự GSM-7 hoặc 3 ký tự UCS-2 mỗi đoạn cho User Data Header được sử dụng để tái lắp ráp, vì vậy các tin nhắn dài được giới hạn ở 153 ký tự GSM-7 mỗi đoạn hoặc 67 ký tự UCS-2 mỗi đoạn. Một dấu ngoặc kép thông minh, em-dash, hoặc biểu tượng cảm xúc duy nhất hạ cấp toàn bộ tin nhắn xuống UCS-2 và cắt giảm một nửa giới hạn mỗi-đoạn. «Smart Encoding» của Twilio tự động thay thế dấu ngoặc kép cong bằng dấu thẳng để giữ các chiến dịch tiếp thị trong mã hóa rẻ hơn.

Nơi các giới hạn byte thực sự cắn

Ba loại nơi các giới hạn byte (chứ không phải ký tự) sẽ bắt bạn:

Tiêu đề yêu cầu HTTP. Không có tối đa trong đặc tả chính thức, mọi máy chủ đều thực thi một cái. LimitRequestFieldSize của Apache mặc định 8 KB mỗi tiêu đề; large_client_header_buffers của Nginx mặc định 4 × 8 KB; IIS mặc định 16 KB; AWS Application Load Balancer chấp nhận 16 KB mỗi tiêu đề và 60 KB tổng cộng; Cloudflare cho phép 32 KB. Các JWT với các bộ claim phồng to thường xuyên vượt quá mặc định 8 KB của Apache, đó là chế độ hỏng sản xuất phổ biến nhất cho xác thực dựa trên token.

Các khóa lưu trữ đối tượng đám mây. S3 và GCS đều giới hạn các khóa đối tượng ở 1024 byte UTF-8. Azure Blob Storage giới hạn tên blob ở 1024 ký tự (UTF-16 nội bộ). Đối với S3, một tên tệp nặng CJK (3 byte mỗi ký tự) đạt đỉnh tại ~341 ký tự; một tên nặng biểu tượng cảm xúc (4 byte mỗi ký tự) tại ~256, sớm hơn nhiều so với những gì nhà phát triển mong đợi.

Giới hạn hàng và chỉ mục cơ sở dữ liệu. MySQL InnoDB có kích thước hàng 65.535 byte và giới hạn tiền tố khóa chỉ mục 3072 byte trên định dạng hàng DYNAMIC (767 trên COMPACT cũ hơn). Một cột VARCHAR(255) utf8mb4 cần 1020 byte (255 × 4) không gian chỉ mục, ổn trên DYNAMIC, hỏng trên COMPACT. Các tài liệu BSON MongoDB giới hạn ở 16 MB. Các mục DynamoDB giới hạn ở 400 KB (bao gồm tên thuộc tính). Các giá trị Redis giới hạn ở 512 MB.

Các trường hợp sử dụng phổ biến

Các sai lầm phổ biến

  1. Tin tưởng .length của JavaScript cho kích thước byte. .length trả về các đơn vị mã UTF-16, không phải byte và không phải ký tự. Đối với byte UTF-8, hãy sử dụng new TextEncoder().encode(text).length; đối với các ký tự nhìn thấy, hãy sử dụng Intl.Segmenter.
  2. Giả định MySQL utf8 thực sự là UTF-8. Đó là một tập hợp con 3-byte âm thầm bỏ biểu tượng cảm xúc. Luôn sử dụng utf8mb4 (và utf8mb4_unicode_ci cho collation) trên bất kỳ cột nào chạm vào văn bản do người dùng gửi.
  3. Giả định một biểu tượng cảm xúc bằng một byte. Một biểu tượng cảm xúc duy nhất là 4 byte trong UTF-8, 4 byte trong UTF-16 (cặp thay thế). Một trình tự ZWJ gia đình có thể vượt quá 30 byte cho cái trông giống một ký tự duy nhất.
  4. Đếm BOM UTF-8 là nội dung. BOM UTF-8 ba-byte EF BB BF ở đầu một tệp là siêu dữ liệu, không phải văn bản. Hầu hết các công cụ CLI (awk, head, sed) xử lý nó như một phần của trường đầu tiên, đó là nguồn của nhiều lỗi «tại sao tên cột đầu tiên của tôi có một ký tự lạ».
  5. Báo cáo số đếm «byte ASCII» cho văn bản không-ASCII. ASCII không thể đại diện cho các ký tự trên U+007F. Bộ đếm này cảnh báo khi đầu vào chứa không-ASCII để bạn biết cột ASCII không có ý nghĩa.

Thêm các câu hỏi thường gặp

Tại sao một biểu tượng cảm xúc là 4 byte khi các ký tự văn bản chỉ là 1?

UTF-8 sử dụng 1 byte cho ASCII (U+0000 đến U+007F), 2 byte cho Latin mở rộng / Hy Lạp / Kirin / Ả Rập / Do Thái (U+0080 đến U+07FF), 3 byte cho hầu hết các chữ viết CJK và Ấn Độ (U+0800 đến U+FFFF), và 4 byte cho biểu tượng cảm xúc và các ký tự mặt phẳng bổ sung (U+10000 đến U+10FFFF). Một biểu tượng cảm xúc điển hình như 😀 (U+1F600) ở trong mặt phẳng bổ sung và tốn 4 byte. Các biểu tượng cảm xúc kết hợp (ví dụ gia đình 👨‍👩‍👧‍👦) được xây dựng từ nhiều biểu tượng cảm xúc cơ sở được dán cùng nhau với các zero-width joiner; mỗi biểu tượng cảm xúc cơ sở là 4 byte, mỗi joiner là 3 byte, vì vậy một gia đình 4 mất 4×4 + 3×3 = 25 byte cho cái trông giống như một ký tự.

MySQL utf8 thực sự có nghĩa là gì?

Trong MySQL, bí danh bộ ký tự utf8 là một tập hợp con tối đa 3-byte của UTF-8 thực. Nó có thể mã hóa mọi ký tự trong Basic Multilingual Plane của Unicode nhưng không thể lưu trữ biểu tượng cảm xúc hoặc bất kỳ ký tự nào trên U+FFFF. UTF-8 4-byte thực trong MySQL là utf8mb4, có sẵn từ MySQL 5.5.3 (tháng 3 năm 2010), mặc định từ MySQL 8.0 (tháng 4 năm 2018). Nếu bạn có thể thay đổi lược đồ, luôn sử dụng utf8mb4 với collation utf8mb4_0900_ai_ci (hoặc utf8mb4_unicode_ci trên các máy chủ cũ hơn).

Bộ đếm này có bao gồm dấu thứ tự byte UTF-8 không?

Không. Dấu thứ tự byte UTF-8 là ba byte EF BB BF mà Excel trên Windows yêu cầu ở đầu tệp để phát hiện UTF-8. Bộ đếm đo lường byte của văn bản bạn dán; nếu văn bản của bạn tình cờ bắt đầu bằng BOM, ba byte đó được tính là nội dung. Nếu bạn muốn biết liệu byte của tệp có đạt giới hạn hay không, chỉ dán phần thân của tệp, không dán BOM.

Tại sao văn bản tiếng Trung của tôi hiển thị 3 byte mỗi ký tự trong UTF-8?

Hầu như tất cả các chữ tượng hình CJK nằm trong phạm vi Unicode U+4E00 đến U+9FFF (khối CJK Unified Ideographs), mà UTF-8 mã hóa thành mỗi 3 byte. Một câu tiếng Trung 100 ký tự do đó là 300 byte UTF-8. Trong UTF-16, cùng một văn bản là 200 byte (2 byte mỗi ký tự), vì vậy UTF-16 nhỏ gọn hơn cho nội dung chủ yếu là CJK. UTF-8 thắng cho nội dung hỗn hợp Latin-và-CJK vì các ký tự Latin có giá 1 byte mỗi cái thay vì 2.

Văn bản của tôi có được tải lên đâu không?

Không. Bộ đếm byte chạy hoàn toàn trong trình duyệt của bạn. Số lượng byte UTF-8 đến từ API tiêu chuẩn TextEncoder (mọi trình duyệt hiện đại đều hỗ trợ), số lượng UTF-16 và Latin-1 đến từ các vòng lặp đơn giản. Không có yêu cầu mạng, không có cuộc gọi máy chủ, không có ghi nhật ký. Khi trang đã tải, công cụ hoạt động ngoại tuyến. An toàn để kiểm tra mã token API, dữ liệu nội bộ, hoặc bất cứ thứ gì bạn sẽ không dán vào một bộ đếm văn bản của bên thứ ba.

Công cụ liên quan

Bộ đếm ký tự Công cụ Đếm Từ & Ký Tự Trực Tuyến Miễn Phí Máy Tính Thời Gian Đọc Trình Trực quan Hóa Hàm Băm Chuỗi