全形與半形是什麼?差異、轉換時機與實用場景完整解析

你是否曾把表單送出後,系統卻回應「格式錯誤」,但明明目測完全正確?或是在 Excel 排序時,同樣的數字卻排在不一起的地方?這些惱人問題,往往根源於一個看似微小的差異——全形(全角)與半形(半角)字元的混用。本文將完整解析兩者的定義、差異及轉換時機。

1. 全形與半形的定義

在東亞字元集(尤其是 CJK 環境)中,字元依照顯示寬度分為兩大類:

類型英文寬度典型範圍(Unicode)範例
半形Half-width1 個字元寬U+0021–U+007E(ASCII 可見字元)A B C 1 2 ! @ #
全形Full-width2 個字元寬U+FF01–U+FF60(全形 ASCII 對應)A B C 1 2 ! @ #

簡單說:全形字元在等寬字型下佔兩個半形的寬度,設計上讓英數字母能與漢字「等寬對齊」;半形字元則與一般 ASCII 標準相符,是現代電腦程式、URL、程式碼所用的標準字元集。

漢字、平假名、片假名本身就屬於全形範疇,不存在「半形漢字」。本文討論的全形/半形轉換,主要針對英文字母、數字、標點符號這三類存在雙版本的字元。

2. 全形與半形的具體差異

以下對照幾個最常見的字元類別:

類別半形全形
大寫英文A B C ZA B C Z
小寫英文a b c za b c z
數字0 1 2 90 1 2 9
常用標點! @ # $ % ( ) ,! @ # $ % ( ) ,
空白(普通空格 U+0020) (表意文字空格 U+3000)

這些字元在外觀上「看起來一樣」,但它們的 Unicode 碼點完全不同,電腦在比較、搜尋、排序時會視為完全不同的字元。這正是混用時出問題的根本原因。

3. 為什麼會出現混用?

全形字元的出現有其歷史脈絡。早期的 CJK 字元集(如 Big5、Shift-JIS)為了讓英數標點能與漢字混排時整齊對齊,在編碼中收錄了全形版本的 ASCII 字元。輸入法(尤其是日語 IME、繁體中文輸入法)通常提供「全角模式」切換,讓使用者在同一輸入模式下打出全形英數。

常見的混用來源:

  • 輸入法在全形模式下輸入的數字、標點(例如在中文輸入模式下打出的逗號 是全形,英文逗號 , 是半形)。
  • 從 Word、PDF、掃描件複製貼上的文字。
  • 使用者對全形半形模式不自知(手機鍵盤、日文 IME 尤其常見)。
  • 不同系統之間的資料交換,原始資料已含有全形字元。

4. 什麼時候需要轉換?

以下幾個場景最容易踩坑,也是最需要轉換的時機:

4.1 表單驗證與資料庫儲存

使用者填寫電話號碼 02-2300-1234(全形數字+連字號),正規表達式 /^\d{2}-\d{4}-\d{4}$/ 完全無法匹配,因為全形數字不屬於 \d。解法:在後端接收資料後,先執行全形→半形正規化,再進行格式驗證。

4.2 搜尋與比對

資料庫中存著半形 iPhone,使用者卻搜尋全形 iPhone,結果一筆也找不到。若搜尋引擎未做字元正規化,這類問題需在應用層統一轉換。

4.3 CSV / Excel 資料處理

數字欄位夾雜全形,讓 Excel 的 SUM() 把那格視為文字而跳過;或排序時全形數字 排在 9 後面,而非數值正確位置。

4.4 程式碼與設定檔

JSON、YAML、.env 等設定檔若混入全形引號 或全形冒號 ,解析器會直接報錯。這種錯誤有時肉眼極難察覺。

4.5 URL 與 Email 地址

全形字元不能直接出現在 URL 或 Email 地址中。例如 user@example.com 中有全形 (U+FF20),郵件系統通常無法辨識。

4.6 排版對齊

反過來,全形→半形並非萬能方向。在某些傳統排版場景(如印刷、台灣政府公文格式)中,標點符號要求使用全形,半形標點反而被視為格式錯誤。此時需要半形→全形的轉換。

5. 轉換規則與注意事項

全形 ASCII 字元(U+FF01–U+FF5E)與半形(U+0021–U+007E)之間的轉換規則非常簡單:

// 全形 → 半形(以 JavaScript 為例)
function toHalfWidth(str) {
    return str.replace(/[\uFF01-\uFF5E]/g, ch =>
        String.fromCharCode(ch.charCodeAt(0) - 0xFEE0)
    ).replace(/\u3000/g, ' ');  // 全形空格 → 半形空格
}

// 半形 → 全形
function toFullWidth(str) {
    return str.replace(/[\u0021-\u007E]/g, ch =>
        String.fromCharCode(ch.charCodeAt(0) + 0xFEE0)
    ).replace(/ /g, '\u3000');  // 半形空格 → 全形空格
}

轉換時有幾個細節值得注意:

  • 漢字與假名不受影響:轉換函式只需針對 Fullwidth ASCII(U+FF01–U+FF5E)與 ASCII(U+0021–U+007E)的對應區段操作,漢字完全不在此範圍。
  • 全形空格(U+3000,表意文字空格)需單獨處理,因為它不在 U+FF01–U+FF5E 的區段內。
  • 片假名的半形版本(U+FF65–U+FF9F)是另一獨立區段,與全形 ASCII 的轉換邏輯不同,需另外處理。
  • 不要盲目雙向轉換:先確認目標系統期望接收的是全形還是半形,再決定轉換方向。

6. 各語言/平台內建支援

語言 / 平台全形→半形說明
PHPmb_convert_kana($str, 'a')'a' 轉全形字母→半形,'A' 反向;需 mbstring 擴充
Pythonunicodedata + str.translate標準庫無直接函式,需自行實作對應表或使用 jaconv 套件
JavaScript正規表達式(見上方)無內建函式,需自行實作
Java自行實作或 Apache Commons無標準函式庫直接支援
MySQL無內建需在應用層處理後再存入
ExcelASC() / JIS()ASC() 全形→半形,JIS() 半形→全形(限日文環境)

7. 實戰建議:資料收集時的正規化策略

與其每次用到資料才轉換,不如在資料進入系統的入口統一正規化:

  1. 後端收到表單資料後立即正規化:電話、郵遞區號、信用卡號等格式敏感欄位,在驗證前先轉半形。
  2. 搜尋查詢也要正規化:搜尋關鍵字與被搜尋資料使用同一字元標準,確保命中率。
  3. 匯入 CSV 時做前置清洗:使用腳本在匯入資料庫前掃描並轉換帶有全形字元的欄位。
  4. 在設定檔 Lint 中加入全形字元偵測:利用 CI/CD 的 pre-commit hook 或 linter 在上線前攔截意外混入的全形字元。
小撇步
不確定文字中有沒有全形字元?把文字貼到文字轉換工具,切換到「半形化」後若輸出與輸入不同,就代表原本含有全形字元。這是快速偵測的有效方法。

8. 小結

全形與半形的差異雖小,但在資料驗證、搜尋、程式開發與排版等場景中都可能造成不可忽視的問題。核心原則很簡單:

  • 程式邏輯、URL、API、資料庫索引欄位 → 優先使用半形
  • 傳統中日韓排版、政府公文、印刷稿 → 依規範使用全形標點。
  • 在系統邊界做一次性正規化,而非到處修補。

遇到需要批次轉換的場合,可以使用本站的文字轉換工具,快速完成全形↔半形互轉,省去手動處理的時間。