Văn bản thực chất là gì, và vì sao các công cụ không thống nhất về nó
Một file văn bản là các byte cộng với một bảng mã, và bảng mã không được lưu trong file. Chỉ có quy ước mới cho chương trình biết một byte nào đó nghĩa là “é” — vì vậy cùng một file mở đúng ở chỗ này nhưng lại hiện thành “é” ở chỗ khác. UTF-8 là câu trả lời hiện đại: lưu các chữ Latin thông dụng trong một byte, chữ có dấu trong hai byte, và phần lớn chữ Trung, Nhật, Ả Rập cùng mọi emoji trong ba hoặc bốn byte. UTF-16 là thứ Windows và JavaScript dùng bên trong, lưu gần như mọi thứ trong hai byte và phần còn lại trong bốn byte. Windows-1252 và Latin-1 là các bảng mã một byte mà hệ thống cũ vẫn tạo ra, và thường là thủ phạm gây lỗi font (mojibake). Điều nên biết về các trang này: Xem file CSV tự nhận diện bảng mã của file bạn thả vào, kể cả UTF-16 và Windows-1252, và cho phép bạn chọn lại. Các ô văn bản thuần thì không — file thả vào được đọc theo UTF-8, nên file xuất theo Latin-1 sẽ hiện sai các chữ có dấu, và cách sửa là chuyển đổi nó trước.
“Ký tự” có bốn nghĩa, và nghĩa bạn cần tùy vào bên nào đặt giới hạn. Thứ con người thấy là một ký tự là một cụm grapheme. Thứ biểu thức chính quy khớp là một code point. Thứ string.length của JavaScript trả về là số đơn vị UTF-16. Thứ một cột cơ sở dữ liệu hay một header HTTP đo là số byte UTF-8. Với tiếng Anh thông thường, cả bốn đều khớp nhau, nên chẳng ai để ý — rồi một emoji gia đình là một grapheme, bảy code point, mười một đơn vị UTF-16 và hai mươi lăm byte, và một tin nhắn 200 ký tự bị một trường 255 ký tự từ chối. Đếm ký tự hiển thị cả bốn chính vì lý do này.
Ký tự vô hình vẫn là ký tự thật. Dấu cách không ngắt dòng trông y hệt dấu cách thường nhưng là một ký tự hoàn toàn khác — nó thường xuyên đi theo văn bản sao chép từ trang web hay trình soạn thảo, và làm hỏng việc tìm kiếm, phân tích CSV và mã tách chuỗi theo dấu cách. Ký tự nối độ rộng bằng 0 là thứ giữ một emoji nhiều người lại với nhau. Dấu gạch nối mềm, dấu chỉ hướng và dấu thứ tự byte (BOM) đều đi kèm văn bản được dán. Không ký tự nào hiện trên màn hình, nên dấu hiệu duy nhất bạn có là một con số đếm không khớp với những gì bạn thấy — đó là một công dụng thực sự của công cụ đếm ký tự. Lưu ý rằng tùy chọn bỏ qua khoảng trắng trong So sánh văn bản gộp các dấu cách và tab thông thường; nó không coi dấu cách không ngắt dòng là dấu cách, vì chúng không phải cùng một thứ.
Ký tự xuống dòng là lý do đôi khi bản so sánh hiện mọi dòng đều thay đổi. Windows kết thúc dòng bằng ký tự về đầu dòng (CR) và xuống dòng (LF); mọi hệ thống khác chỉ dùng LF. Lưu một file LF bằng trình soạn thảo trên Windows là mọi dòng trong đó giờ khác đi một byte vô hình, nên công cụ so sánh theo byte — git diff, diff(1) — báo cả file đã bị viết lại và che mất đúng một thay đổi bạn thực sự làm. So sánh văn bản và Xóa dòng trùng lặp của chúng tôi tách dòng theo cả ba quy ước trước khi so sánh, nên một file chỉ đổi ký tự xuống dòng sẽ không hiện ra ở đây như một bức tường màu đỏ. Đó là tiện ích với một công cụ để đọc, nhưng là cái bẫy trong một repository: hãy sửa từ gốc bằng trình soạn thảo hoặc bằng cài đặt xuống dòng của chính git.
Hai chuỗi trông giống hệt nhau vẫn có thể bị so là khác nhau, và nguyên nhân thường là chuẩn hóa Unicode. Unicode có thể viết “é” theo hai cách: một code point duy nhất, hoặc chữ “e” thường theo sau là dấu sắc tổ hợp. Chúng hiển thị giống nhau nhưng là hai chuỗi byte khác nhau, nên phép so sánh, việc loại trùng hay truy vấn cơ sở dữ liệu đều coi chúng là hai giá trị khác nhau. macOS và Windows từ trước đến nay không thống nhất nên dùng dạng nào cho tên file, và đó là lý do một danh sách gom từ hai máy lại có những mục trông như trùng hệt nhau mà không loại trùng được. Đếm ký tự là cách để bạn phát hiện — hai dạng có cùng số grapheme nhưng khác số code point. Không công cụ nào ở đây chuyển đổi giữa hai dạng; đó là việc một dòng mã với thư viện Unicode, chẳng hạn unicodedata.normalize của Python.
“Số từ” là một phán đoán, không phải phép đo. Tách từ theo khoảng trắng là quy tắc của tiếng Anh, và áp dụng nó cho tiếng Trung, tiếng Nhật hay tiếng Thái — vốn không đặt khoảng trắng giữa các từ — sẽ báo cả một bài viết dài là một từ. Công cụ đếm của chúng tôi dùng phân đoạn từ Unicode của trình duyệt thay vào đó, vốn biết từ bắt đầu ở đâu trong mọi hệ chữ viết. Những khác biệt còn lại nằm ở dấu gạch nối (“well-known” là một từ ở đây và trong Word, là hai từ ở một số công cụ khác), các con số đứng riêng, và thế nào là một câu — “We met Dr. Smith” là một câu nhưng bộ tách câu đơn giản sẽ nói là hai. Thời gian đọc là một ước tính nữa chồng lên trên: 238 từ mỗi phút khi đọc thầm, lấy từ một phân tích tổng hợp chứ không phải con số tròn hay được chép qua lại giữa các bài blog.
Khi nào trình duyệt thực sự không phải công cụ phù hợp
Không có gì trong nhóm công cụ này được gửi đi hay lưu trữ, nên bạn có thể yên tâm dán bản nháp chưa công bố hay mã nguồn độc quyền vào. Nhưng điều đó cũng đặt ra giới hạn, và chúng tôi muốn nói rõ giới hạn ở đâu hơn là để bạn phát hiện ra giữa chừng.
File lớn. Toàn bộ văn bản được giữ trong bộ nhớ của tab và được xử lý lại mỗi khi bạn gõ. Vài megabyte thì thoải mái; một file log vài trăm megabyte thì không, và điện thoại sẽ bỏ cuộc sớm hơn laptop. Dòng lệnh không gặp vấn đề này vì nó xử lý theo luồng: grep và ripgrep tìm trong những file lớn hơn cả bộ nhớ máy, sed và awk biến đổi chúng từng dòng một, còn sort với cờ unique loại trùng một danh sách hàng chục triệu dòng bằng cách ghi tạm ra ổ đĩa. Tất cả đều miễn phí và có sẵn trên macOS và Linux.
Hai tài liệu khác nhau quá nhiều. So sánh văn bản dừng ở 8.000 điểm khác biệt, vì vượt quá mức đó, bộ nhớ thuật toán cần tăng nhanh đến mức làm treo tab, và một bản so sánh lớn cỡ đó cũng chẳng đọc nổi. Hai phiên bản của cùng một tài liệu gần như không bao giờ chạm tới; hai tài liệu không liên quan thì chạm tới ngay. Để review mã, diff và git diff xử lý được mọi kích thước, và một công cụ merge ba chiều đúng nghĩa làm được việc mà trang này hoàn toàn không làm được.
Đổi bảng mã hoặc chuẩn hóa Unicode. Các trang này đọc và báo cáo; chúng không chuyển đổi giữa các bảng mã. iconv chuyển đổi giữa mọi bảng mã hiện có, lệnh file đoán xem bạn đang có bảng mã gì, còn chuẩn hóa Unicode chỉ là một dòng Python hoặc một lệnh gọi uconv của ICU. Nếu bạn đang sửa một file xuất bị lỗi phông, đó là bộ công cụ cần dùng.
Bất cứ việc gì lặp đi lặp lại. Các công cụ này chạy khi có người bấm. Đếm từ trong bốn trăm tài liệu, hay nén cả một thư mục mỗi lần commit, là việc của script hoặc một bước build — và riêng với việc nén mã, công cụ build của bạn cũng nén đúng như vậy, kèm source map, chế độ theo dõi thay đổi và bộ nhớ đệm mà một ô dán văn bản không thể có. Trang này dành cho một file bạn đang có trước mặt.
CSS hiện đại. Nén CSS từ chối cú pháp lồng nhau (nesting) gốc và cú pháp khoảng giá trị media hiện đại thay vì nén chúng, vì bộ nén đứng sau nó ra đời trước cả hai và lặng lẽ xóa những gì nó không hiểu. Đó là một sự từ chối thẳng thắn chứ không phải tính năng, và cách giải quyết là biên dịch bỏ phần lồng nhau trước bằng Sass, PostCSS hoặc Lightning CSS — việc mà công cụ build của bạn gần như chắc chắn đã làm.
Chọn giữa những công cụ nghe na ná nhau
Đếm số từ hay Đếm ký tự. Cùng một cách đếm, khác con số chính. Đếm số từ ưu tiên số từ, số câu, số đoạn và thời gian đọc — thước đo của một bài luận, một bài viết hay một bài phát biểu. Đếm ký tự ưu tiên số ký tự, số ký tự không tính dấu cách và số byte UTF-8 — thước đo của một thẻ meta description, một tin nhắn SMS hay một trường cơ sở dữ liệu. Nếu có thứ gì đó từ chối văn bản của bạn vì quá dài, bạn cần công cụ đếm ký tự, và cụ thể là số byte của nó.
So sánh văn bản hay Xóa dòng trùng lặp. So sánh văn bản trả lời câu hỏi “hai phiên bản này khác nhau ở đâu” và cần hai đoạn văn bản. Xóa dòng trùng lặp làm việc trên một danh sách và trả lời “thứ gì xuất hiện nhiều hơn một lần ở đây”, đồng thời còn cho bạn biết mục nào bị lặp và lặp bao nhiêu lần, sắp xếp tự nhiên để item2 đứng trước item10, hoặc chỉ giữ lại những dòng xuất hiện đúng một lần. Tìm những mục chỉ có trong một trong hai danh sách là việc của Xóa dòng trùng lặp, không phải của So sánh văn bản.
Nén HTML, Nén CSS hay Nén JavaScript. Ba ngôn ngữ, ba công cụ nén, và một điểm chồng lấn nên biết: Nén HTML cũng nén CSS bên trong thẻ style và JavaScript bên trong thẻ script, giống hệt cách hai trang kia làm. Vì vậy một file HTML chỉ cần một công cụ, không phải ba. File .css và .js riêng thì cần trang riêng của chúng.
Xem file XML hay Định dạng XML và Kiểm tra XML. Trình xem ở đây cho bạn một cây thu gọn được để khám phá, đúng thứ bạn cần khi tài liệu lớn và bạn đang tìm một thứ gì đó. Định dạng XML và Kiểm tra XML, trong nhóm công cụ lập trình, cho bạn văn bản đã thụt lề để dán lại vào file, và dòng, cột chính xác của chỗ bị lỗi. Một bên để đọc, một bên để chỉnh sửa và sửa lỗi.
Xem file CSV hay mở file bằng Excel. Không phải công cụ cạnh tranh, nhưng đó là phép so sánh mà người ta thực sự đang làm. Excel tự chuyển đổi khi mở và không hề hỏi: mã sản phẩm 00123 thành 123, mã linh kiện 5-3 thành ngày 5 tháng 3, số đơn hàng dài thành ký hiệu khoa học, và file xuất phân cách bằng dấu chấm phẩy từ một hệ thống của Đức bị dồn hết vào cột A. Trình xem hiển thị mọi giá trị dưới dạng văn bản, đúng như được lưu, để bạn thấy mình thực sự được gửi gì.
Xem trước Markdown hay Chuyển Markdown sang PDF. Xem trước dùng để kiểm tra một file README có hiển thị đúng như GitHub sẽ hiển thị hay không, ngay khi bạn gõ. Chuyển Markdown sang PDF, trong nhóm công cụ tài liệu, dùng để tạo ra một tài liệu hoàn chỉnh có ngắt trang. Kiểm tra ở đây, xuất bản ở đó.