0

Lọc và đếm chữ Hán trong chuỗi bằng Unicode property escapes của JavaScript

Khi làm công cụ học tiếng Trung, việc đầu tiên thường gặp là lọc chữ Hán ra khỏi một chuỗi lẫn pinyin, dấu câu, số và chữ Latin: để đếm tần suất chữ trong lời bài hát, để tạo thẻ từ, hay để kiểm người dùng có gõ đúng chữ không. Bài này dùng Unicode property escapes của JavaScript để làm việc đó gọn và đúng.

Đừng dùng khoảng mã \u4e00-\u9fff

Nhiều đoạn code trên mạng lọc chữ Hán bằng /[\u4e00-\u9fff]/. Khoảng này chỉ là khối CJK Unified Ideographs cơ bản. Nó bỏ sót các khối mở rộng (Extension A, B và các khối sau), nơi có nhiều chữ hiếm, chữ dùng trong tên người, địa danh và chữ phồn thể ít gặp.

Dùng \p{Script=Han}

Từ ES2018, regex có cờ u hỗ trợ thuộc tính Unicode. \p{Script=Han} khớp mọi ký tự thuộc hệ chữ Hán, kể cả các khối mở rộng.

const HAN = /\p{Script=Han}/gu;

function demChuHan(text) {
  const dem = new Map();
  for (const ch of text.match(HAN) || []) dem.set(ch, (dem.get(ch) || 0) + 1);
  return [...dem].sort((a, b) => b[1] - a[1]);
}

demChuHan('我想你。你想我吗?我们明天见。').slice(0, 4);
// [['我', 3], ['想', 2], ['你', 2], ['吗', 1]]

Bẫy độ dài chuỗi

Chữ ở khối Extension B trở đi nằm ngoài BMP, được lưu bằng một cặp surrogate. Vì vậy '𠀀'.length bằng 2 dù chỉ là một chữ. Cờ u giúp regex coi cặp đó là một ký tự, nên '𠀀'.match(/\p{Script=Han}/gu).length bằng 1. Khi cắt chuỗi hay đếm ký tự, dùng [...text] hoặc Array.from(text) thay vì text.length và slice.

Dấu câu tiếng Trung

Dấu câu toàn chiều rộng như 。, ,, ?, ! không thuộc Script=Han, nên tự động bị loại. Muốn giữ dấu câu thì dùng thêm \p{P}.

Ứng dụng

Đếm tần suất chữ trên lời bài hát, phụ đề phim hay một bộ giáo trình cho biết nên dạy chữ nào trước. Đây cũng là cách nhiều tài liệu học xếp từ theo tần suất thực tế thay vì theo chủ đề. Ví dụ về bộ từ xếp theo tần suất cho người Việt học tiếng Trung có trên Từ Vựng 123.


All Rights Reserved

Viblo
Let's register a Viblo Account to get more interesting posts.