﻿# 整理 Unicode 經常會使用到的內碼區域並透過 Regex 自動比對文字

最近有個案子需要設法過濾表單中輸入的文字，有些欄位只能輸入英數字，有些則必須自動轉全形文字，還有些只能輸入中文，有些不允許輸入標點符號。這個需求照理說很簡單，透過 Regular Expression 一下子就可以達陣，但是光是完成這功能實在太無趣了，所以晚上徹底的研究並整理所有的 Unicode 編碼，發現許多有趣的冷知識。

本篇文章我打算整理出常用的 Unicode 內碼區域，並透過 JavaScript 正則表示式(Regular Expression)比對出這些文字，有些 Patterns 應該蠻實用的，可以直接複製貼上回去使用。

### UTF-8 相容於 [ASCII](http://www.asciitable.com/) 的文字範圍

1.  數字 (Numbers)
    
    ```
    [0-9]
    ```
    
    ```
    [\u0030-\u0039]
    ```
    
2.  英文字母 (Alphabets)
    
    ```
    [A-Za-z]
    ```
    
    ```
    [\u0041-\u005A\u0061-\u007A]
    ```
    
3.  空白字元 (Space)
    
    ```
    [ ]
    ```
    
    ```
    [\s]
    ```
    
    ```
    [\u0020]
    ```
    
4.  控制字元 ([Control Codes](https://en.wikipedia.org/wiki/List_of_Unicode_characters#Control_codes)) (共 65 個字元，包含 [DEL](https://en.wikipedia.org/wiki/Delete_character) 但不包含 [SP](https://en.wikipedia.org/wiki/Space_\(punctuation\)) 空白字元 )
    
    C0 包含 `\u0000-\u001F\u007F`，C1 包含 `\u0080-\u009F`
    
    ```
    [\u0000-\u001F\u007F\u0080-\u009F]
    ```
    
5.  標點符號 (Punctuation & Symbols)
    
    ```
    [\u0021-\u002F\u003A-\u0040\u005B-\u0060\u007B-\u007E]
    ```
    
    ```
    [~!@#$%^&*()_+=\-`\[\]{}';:".,<>/?\|]
    ```
    
6.  基本拉丁文字 ([Basic Latin](https://en.wikipedia.org/wiki/List_of_Unicode_characters#Basic_Latin)) (包含字母、數字與標點符號)
    
    ```
    [\u0020-\u002F\u0030-\u0039\u003A-\u0040\u0041-\u005A\u005B-\u0060\u0061-\u007A\u007B-\u007E]
    ```
    

### 超出 ASCII 範圍的補充拉丁文字 (較少用到)

1.  Latin-1 補充文字 ([Latin-1 Supplement](https://en.wikipedia.org/wiki/List_of_Unicode_characters#Latin-1_Supplement)) (中文鍵盤打不出來的字)
    
    ```
    [\u00A0-\u00BF\u00C0-\u003FF]
    ```
    
2.  Latin 擴充文字 A ([Latin Extended-A](https://en.wikipedia.org/wiki/List_of_Unicode_characters#Latin_Extended-A)) (中文鍵盤打不出來的字)
    
    ```
    [\u0100-\u017F]
    ```
    
3.  Latin 擴充文字 B ([Latin Extended-B](https://en.wikipedia.org/wiki/List_of_Unicode_characters#Latin_Extended-B)) (中文鍵盤打不出來的字)
    
    ```
    [\u0180-\u024F]
    ```
    
4.  Latin 擴充附加文字 ([Latin Extended Additional](https://en.wikipedia.org/wiki/List_of_Unicode_characters#Latin_Extended_Additional)) (中文鍵盤打不出來的字)
    
    ```
    [\u1E02-\u1EF3]
    ```
    

### 漢字 Unicode 範圍 ([Han unification](https://en.wikipedia.org/wiki/Han_unification))

1.  中日韓統一表意文字列表 ([CJK Unified Ideographs](https://en.wikipedia.org/wiki/CJK_Unified_Ideographs_\(Unicode_block\)))
    
    簡單來說，就是「所有的漢字」都在這個範圍裡，包含正體中文、簡體中文與日文、韓文、越南文裡的漢字。
    
    ```
    [\u4E00-\u9FFF]
    ```
    
2.  中日韓統一表意文字擴展區 A ([CJK Unified Ideographs Extension A](https://en.wikipedia.org/wiki/CJK_Unified_Ideographs_Extension_A))
    
    這是 1997 年提出的擴充漢字，大多是罕見字，所有文字都不存在於 Big5 編碼中。有些俗稱的「難字」有可能會落在這區 Unicode 文字中。
    
    ```
    [\u3400-\u4DBF]
    ```
    
3.  中日韓相容表意文字區 ([CJK Compatibility Ideographs](https://en.wikipedia.org/wiki/CJK_Compatibility_Ideographs)) (`不建議使用的區域`)
    
    這區的文字是指中日韓越統一表意文字中因為字源分離原則未與正式字集（包括擴展 A、B、C、D 區）中的字形統一的字。
    
    ```
    [\uF900-\uFAFF]
    ```
    
    ※ 簡單來說，這區的文字不要用，因為許多「第三方字型」都沒有實作這個區域的文字。
    
4.  全形空白
    
    ```
    [\u3000]
    ```
    
5.  中日韓相容形式 ([CJK Compatibility Forms](https://en.wikipedia.org/wiki/CJK_Compatibility_Forms)) (`不建議使用的區域`)
    
    對於一些「垂直書寫」的文字系統中會用到的標點符號，都集中整理到這個區域內。不建議使用。
    
    ```
    [\uFE30-\uFE4F]
    ```
    
6.  中日韓標點符號 ([CJK Symbols and Punctuation](https://en.wikipedia.org/wiki/CJK_Symbols_and_Punctuation)) (沒有包含所有全形標點符號)
    
    在中日韓語中經常使用的標點符號，都會出現在這個區域內。以下 Patterns 包含全形空白 ( `\u3000` )：
    
    ```
    [\u3000\u3001-\u303F]
    ```
    
    但台灣常用與中文書寫相關的標點符號(括弧、頓號、句號)，應該只有以下這些：
    
    ```
    [\u3000-\u3003\u3008-\u300F\u3010-\u3011\u3014-\u3015\u301C-\u301E]
    ```
    
7.  全形英文或標點符號 ([Halfwidth and Fullwidth Forms](https://en.wikibooks.org/wiki/Unicode/Character_reference/F000-FFFF))
    
    ```
    [\uFF01-\uFF5E]
    ```
    
    這個區域比較有趣的地方是，這些全形英文與全形標點符號的排列順序，剛好跟 ASCII 的排列順序一樣。這也意味者，我們只要將**特定範圍內**的 ASCII 內碼，加上 `65248` ( `FEE0` ) 偏移量，就會自動算出全形的 Unicode 文字。
    
    以下就是我用 JavaScript 寫成的半形轉全形範例程式，這裡的 Magic Number `65248` 就是這麼來的！
    
    ```javascript
    function half2full(str) {
      let len = str.length;
      let res = [];
      for (let i = 0; i < len; i++) {
        let c = str.charCodeAt(i);
        if (c >= 0x21 && c <= 0x7e) {
          res.push(String.fromCharCode(c + 65248));
        } else {
          res.push(str[i]);
        }
      }
      return res.join('');
    }
    ```
    

### 常用 Unicode 符號

1.  空白字元 ([Whitespace character](https://en.wikipedia.org/wiki/Whitespace_character))
    
    有寬度的空白字元
    
    ```
    [\u0009-\u000D\u0020\u0085\u00A0\u1680\u2000-\u200A\u2028-\u2029\u202F\u205F\u3000]
    ```
    
    零寬度的空白字元 (zero width whitespaces)
    
    ```
    [\u180E\u200B-\u200D\u2060\uFEFF]
    ```
    
2.  空白的替代字元 (有形的空白字元)
    
    當需要特別強調空白字元或是在列印輸出時想特別告知這是空白時，可以用的空白替代字元。詳見 [Substitutes](https://en.wikipedia.org/wiki/Whitespace_character#Substitutes) 連結。
    
    ```
    [\u00B7\u237D\u2420\u2422\u2423]
    ```
    
3.  通用 Unicode 標點符號 ([General Punctuation](https://en.wikipedia.org/wiki/General_Punctuation))
    
    ```
    [\u2000-\u206F]
    ```
    

### Unicode 使用者造字區 (Private Use Area)

1.  如果你真的需要用到 Unicode 尚未定義的文字，可以使用以下區域：
    
    ```
    [\uE000-\uF8FF]
    ```
    
    ※ 這個區域可以讓你自訂 6,400 個字，應該是綽綽有餘！
    
2.  BIG5 與 Unicode 的使用者造字區對應
    
    BIG5 是一套雙位元組字元集，使用了雙八碼儲存方法，以兩個位元組來組成一個中文字。第一個位元組稱為「高位位元組」，第二個位元組稱為「低位位元組」。
    
    BIG5 中「高位位元組」使用了 `0x81-0xFE` (共 126 個字元)，「低位位元組」使用了 `0x40-0x7E` 與 `0xA1-0xFE` (僅使用 157 個字元)，最多只能定義 `19,782` 個字碼。
    
    在 [BIG5](https://zh.wikipedia.org/wiki/%E5%A4%A7%E4%BA%94%E7%A2%BC) 編碼中，共定義出四個使用者造字區：
    
    1.  `0xFA40 ~ 0xFEFE` 對應到 Unicode 編碼的 `U+E000 ~ U+E310]` (總共 `785` 個字)
    2.  `0x8E40 ~ 0xA0FE` 對應到 Unicode 編碼的 `U+E311 ~ U+EEB7]` (總共 `2,983` 個字)
    3.  `0x8140 ~ 0x8DFE` 對應到 Unicode 編碼的 `U+EEB8 ~ U+F6B0]` (總共 `2,041` 個字)
    4.  `0xC6A1 ~ 0xC8FE` 對應到 Unicode 編碼的 `U+F6B1 ~ U+F848]` (總共 `408` 個字)
    
    如果你的系統需要跟 BIG5 相容，那麼你應該只能使用上述範圍的 Unicode 編碼，此時你的正則表示式應該改寫如下：
    
    ```
    [\uE000-\uF848]
    ```
    

### 關於 BIG5 與 Unicode 的字碼對應表

由於大家比較耳熟能詳的是 [BIG5](https://en.wikipedia.org/wiki/Big5) 編碼，但其實在 Windows 作業系統中，預設內建的是 [CP950](https://en.wikipedia.org/wiki/Code_page_950) 編碼，他擴充了一些 BIG5 缺少的常用文字與符號，例如它在 `F9D6-F9FE` 添加了 7 個倚天中文系統增加的字元「碁銹裏墻恒粧嫺」和 34 個畫圖和製表符號 (參見 [程式碼頁面950 - 維基百科，自由的百科全書](https://zh.wikipedia.org/wiki/%E4%BB%A3%E7%A2%BC%E9%A0%81950) 說明)。

由於 CP950 到 Unicode 之間並沒有特定的順序，也沒有公式可以轉換 (只有**造字區**[有公式](https://en.wikipedia.org/wiki/Code_page_950#Private_Use_Area_usage)可以轉換)，所以必須靠查表的方式逐一對應才行。在 Unicode.org 官網上有提供完整的 [CP950 到 Unicode 的對應表](https://www.unicode.org/Public/MAPPINGS/VENDORS/MICSFT/WINDOWS/CP950.TXT)，下載之後就可以輕易做出一份自己的對應表。

這裡有幾個常用的 BIG5 內碼區域，方便日後查表參考：

-   `0xA140-0xA3BF`: 標點符號、希臘字母及特殊符號，包括在0xA259-0xA261，安放了九個計量用漢字：`兙兛兞兝兡兣嗧瓩糎`。
-   `0xA440-0xC67E`: 常用漢字，先按筆劃再按部首排序。
-   `0xC940-0xF9D5`: 次常用漢字，亦是先按筆劃再按部首排序。

**相關連結**

-   [Unicode - Wikipedia](https://en.wikipedia.org/wiki/Unicode)
    -   [UTF-8 - Wikipedia](https://en.wikipedia.org/wiki/UTF-8) ( [中文](https://zh.wikipedia.org/wiki/UTF-8) )
    -   [Unicode 11.0.0](http://unicode.org/versions/Unicode11.0.0/) - 2018 June 5
    -   [List of Unicode characters - Wikipedia](https://en.wikipedia.org/wiki/List_of_Unicode_characters)
    -   [Unicode/Character reference/0000-0FFF](https://en.wikibooks.org/wiki/Unicode/Character_reference/0000-0FFF)
-   [Han unification - Wikipedia](https://en.wikipedia.org/wiki/Han_unification)
    -   [Unicode ranges](https://en.wikipedia.org/wiki/Han_unification#Unicode_ranges)
    -   [CJK characters - Wikipedia](https://en.wikipedia.org/wiki/CJK_characters)
    -   [CJK Unified Ideographs - Wikipedia](https://en.wikipedia.org/wiki/CJK_Unified_Ideographs)
    -   [List of CJK fonts - Wikipedia](https://en.wikipedia.org/wiki/List_of_CJK_fonts)
-   [大五碼 - 維基百科，自由的百科全書](https://zh.wikipedia.org/wiki/%E5%A4%A7%E4%BA%94%E7%A2%BC) ([Big5](https://en.wikipedia.org/wiki/Big5))
    -   [Code page 950 - Wikipedia](https://en.wikipedia.org/wiki/Code_page_950)
    -   [Big 5 Code Tables](http://www.khngai.com/chinese/charmap/tblbig.php)
    -   [Unicode補完計畫 - 維基百科，自由的百科全書](https://zh.wikipedia.org/wiki/Unicode%E8%A3%9C%E5%AE%8C%E8%A8%88%E7%95%AB)
    -   [ISO 10646 漢字查詢系統](http://glyph.iso10646hk.net/ccs/ccs.jsp?lang=zh_TW)
    -   [CP950 到 Unicode 的對應表](https://www.unicode.org/Public/MAPPINGS/VENDORS/MICSFT/WINDOWS/CP950.TXT)
    -   [BIG5 到 Unicode 的對應表](ftp://ftp.unicode.org/Public/MAPPINGS/OBSOLETE/EASTASIA/OTHER/BIG5.TXT)
-   [javascript - How to use regular expression to validate Chinese input? - Stack Overflow](https://stackoverflow.com/questions/40099273/how-to-use-regular-expression-to-validate-chinese-input)
