{"slug":"unicode-cjk-lap-trinh-xu-ly-103000-ky-tu-han-nom","title":"Unicode CJK Cho Lập Trình Viên: Xử Lý 103,000+ Ký Tự Hán-Nôm","summary":"Hướng dẫn xử lý Unicode CJK cho lập trình viên: các block ký tự, surrogate pairs trong JavaScript, nhận dạng CJK, database collation, và chuyển đổi giản/phồn thể.","excerpt":"Hướng dẫn xử lý Unicode CJK cho lập trình viên: các block ký tự, surrogate pairs trong JavaScript, nhận dạng CJK, database collation, và chuyển đổi giản/phồn thể.","markdown":"# Unicode CJK Cho Lập Trình Viên\nChuyên mục: Lập trình × Ngôn ngữ\n\nXử lý ký tự CJK (Chinese-Japanese-Korean) trong lập trình đặt ra nhiều thách thức: từ encoding, surrogate pairs, đến normalization. Bài viết tổng hợp kiến thức cần thiết cho developer.\n\n## 1. CJK Trong Unicode: Các Block Chính\nUnicode phân bổ ký tự CJK vào nhiều block:\n\n// Block chính\nU+4E00–U+9FFF    CJK Unified      20,992 chars\nU+3400–U+4DBF    Extension A        6,592 chars\nU+20000–U+2A6DF  Extension B       42,720 chars (surrogate pairs!)\nU+2A700–U+2B73F  Extension C        4,149 chars\nU+2B740–U+2B81F  Extension D          222 chars\nU+2B820–U+2CEAF  Extension E        5,762 chars\nU+2CEB0–U+2EBEF  Extension F        7,473 chars\nU+30000–U+3134F  Extension G        4,939 chars\nU+31350–U+323AF  Extension H        4,192 chars\n\n## 2. Surrogate Pairs — Bẫy Cho JavaScript/Java\nKý tự Extension B trở đi (U+20000+) nằm ngoài BMP (Basic Multilingual Plane), cần 2 UTF-16 code units:\n\nconst char = '𠀀'; // U+20000 Extension B\nconsole.log(char.length);        // 2 (KHÔNG PHẢI 1!)\nconsole.log([...char].length);   // 1 (spread operator xử lý đúng)\nconsole.log(char.codePointAt(0)); // 131072 = 0x20000\n\nLuôn dùng codePointAt() thay vì charCodeAt(), và [...str] thay vì str.split('') khi xử lý CJK.\n\n## 3. Nhận Dạng Ký Tự CJK\nfunction isCJK(codePoint) {\nreturn (\n(codePoint >= 0x4E00 && codePoint <= 0x9FFF) ||   // CJK Unified\n(codePoint >= 0x3400 && codePoint <= 0x4DBF) ||   // Ext A\n(codePoint >= 0x20000 && codePoint <= 0x2A6DF) || // Ext B\n(codePoint >= 0x2A700 && codePoint <= 0x2B73F) || // Ext C\n(codePoint >= 0x2B740 && codePoint <= 0x2B81F) || // Ext D\n(codePoint >= 0x2B820 && codePoint <= 0x2CEAF) || // Ext E\n(codePoint >= 0x2CEB0 && codePoint <= 0x2EBEF) || // Ext F\n(codePoint >= 0x30000 && codePoint <= 0x3134F) || // Ext G\n(codePoint >= 0x31350 && codePoint <= 0x323AF) || // Ext H\n(codePoint >= 0xF900 && codePoint <= 0xFAFF)      // Compatibility\n);\n}\n\n## 4. CJK Trong Database: Collation & Indexing\nVấn đề thường gặp khi lưu CJK trong PostgreSQL/MySQL:\n\nCollation: Dùng 'und-x-icu' hoặc 'zh-x-icu' thay vì 'C' để sắp xếp đúng thứ tự Hán tự\nIndexing: pg_trgm hoạt động tốt cho CJK search trong PostgreSQL\nEncoding: Luôn dùng UTF-8, kiểm tra connection encoding\nFull-text search: CJK cần tokenizer đặc biệt (jieba, mecab, ICU)\n## 5. Giản Thể ↔ Phồn Thể Conversion\nChuyển đổi giản thể/phồn thể KHÔNG phải 1-1 mapping. Nhiều ký tự giản thể map đến nhiều ký tự phồn thể tùy context:\n\n// 发 (giản) có thể là:\n// 發 (phát - phát triển) hoặc 髮 (phát - tóc)\n// Cần context để phân biệt!\n// OpenCC library xử lý tốt vấn đề này\n","html":"<p>Chuyên mục: Lập trình × Ngôn ngữ</p>\n<p>Xử lý ký tự CJK (Chinese-Japanese-Korean) trong lập trình đặt ra nhiều thách thức: từ encoding, surrogate pairs, đến normalization. Bài viết tổng hợp kiến thức cần thiết cho developer.</p>\n<h2>1. CJK Trong Unicode: Các Block Chính</h2>\n<p>Unicode phân bổ ký tự CJK vào nhiều block:</p>\n<pre><code>// Block chính\nU+4E00–U+9FFF    CJK Unified      20,992 chars\nU+3400–U+4DBF    Extension A        6,592 chars\nU+20000–U+2A6DF  Extension B       42,720 chars (surrogate pairs!)\nU+2A700–U+2B73F  Extension C        4,149 chars\nU+2B740–U+2B81F  Extension D          222 chars\nU+2B820–U+2CEAF  Extension E        5,762 chars\nU+2CEB0–U+2EBEF  Extension F        7,473 chars\nU+30000–U+3134F  Extension G        4,939 chars</code></pre>\n<p>U+31350–U+323AF  Extension H        4,192 chars</p>\n<h2>2. Surrogate Pairs — Bẫy Cho JavaScript/Java</h2>\n<p>Ký tự Extension B trở đi (U+20000+) nằm ngoài BMP (Basic Multilingual Plane), cần 2 UTF-16 code units:</p>\n<pre><code>const char = &#x27;𠀀&#x27;; // U+20000 Extension B\nconsole.log(char.length);        // 2 (KHÔNG PHẢI 1!)\nconsole.log([...char].length);   // 1 (spread operator xử lý đúng)</code></pre>\n<p>console.log(char.codePointAt(0)); // 131072 = 0x20000</p>\n<p>Luôn dùng codePointAt() thay vì charCodeAt(), và [...str] thay vì str.split(&#x27;&#x27;) khi xử lý CJK.</p>\n<h2>3. Nhận Dạng Ký Tự CJK</h2>\n<pre><code>function isCJK(codePoint) {\n  return (\n    (codePoint &gt;= 0x4E00 &amp;&amp; codePoint &lt;= 0x9FFF) ||   // CJK Unified\n    (codePoint &gt;= 0x3400 &amp;&amp; codePoint &lt;= 0x4DBF) ||   // Ext A\n    (codePoint &gt;= 0x20000 &amp;&amp; codePoint &lt;= 0x2A6DF) || // Ext B\n    (codePoint &gt;= 0x2A700 &amp;&amp; codePoint &lt;= 0x2B73F) || // Ext C\n    (codePoint &gt;= 0x2B740 &amp;&amp; codePoint &lt;= 0x2B81F) || // Ext D\n    (codePoint &gt;= 0x2B820 &amp;&amp; codePoint &lt;= 0x2CEAF) || // Ext E\n    (codePoint &gt;= 0x2CEB0 &amp;&amp; codePoint &lt;= 0x2EBEF) || // Ext F\n    (codePoint &gt;= 0x30000 &amp;&amp; codePoint &lt;= 0x3134F) || // Ext G\n    (codePoint &gt;= 0x31350 &amp;&amp; codePoint &lt;= 0x323AF) || // Ext H\n    (codePoint &gt;= 0xF900 &amp;&amp; codePoint &lt;= 0xFAFF)      // Compatibility\n  );</code></pre>\n<p>}</p>\n<h2>4. CJK Trong Database: Collation &amp; Indexing</h2>\n<p>Vấn đề thường gặp khi lưu CJK trong PostgreSQL/MySQL:</p>\n<ul>\n<li>Collation: Dùng &#x27;und-x-icu&#x27; hoặc &#x27;zh-x-icu&#x27; thay vì &#x27;C&#x27; để sắp xếp đúng thứ tự Hán tự</li>\n<li>Indexing: pg_trgm hoạt động tốt cho CJK search trong PostgreSQL</li>\n<li>Encoding: Luôn dùng UTF-8, kiểm tra connection encoding</li>\n<li>Full-text search: CJK cần tokenizer đặc biệt (jieba, mecab, ICU)</li>\n</ul>\n<h2>5. Giản Thể ↔ Phồn Thể Conversion</h2>\n<p>Chuyển đổi giản thể/phồn thể KHÔNG phải 1-1 mapping. Nhiều ký tự giản thể map đến nhiều ký tự phồn thể tùy context:</p>\n<pre><code>// 发 (giản) có thể là:\n// 發 (phát - phát triển) hoặc 髮 (phát - tóc)\n// Cần context để phân biệt!</code></pre>\n<p>// OpenCC library xử lý tốt vấn đề này</p>","tags":["JCK Font","Lập trình","Ngôn ngữ"],"author":"System Legacy","publishedAt":"2026-04-04T07:37:28.917Z","updatedAt":"2026-07-17T02:34:51.886Z","published_at":"2026-04-04T07:37:28.917Z","updated_at":"2026-07-17T02:34:51.886Z","view_count":181,"canonical":"https://wiki.quizzman.com/wiki/unicode-cjk-lap-trinh-xu-ly-103000-ky-tu-han-nom","url":"https://wiki.quizzman.com/wiki/unicode-cjk-lap-trinh-xu-ly-103000-ky-tu-han-nom","markdownUrl":"https://wiki.quizzman.com/api/articles/unicode-cjk-lap-trinh-xu-ly-103000-ky-tu-han-nom.md","apiUrl":"https://wiki.quizzman.com/api/articles/unicode-cjk-lap-trinh-xu-ly-103000-ky-tu-han-nom"}