在前端表單填寫時,常會遇到後端 API 或驗證規則限定只接受半形字元,但使用者輸入時不小心切換到全形輸入法,導致驗證碼、電話或金額數字變成全形(如
ABC123)而無法通過 Input RegExp 表單驗證 — 只輸入數字。透過 JavaScript 的charCodeAt字元碼位移,即可在前端即時完成全形轉半形處理。
(註:若您需要處理日文片假名、特殊相容符號或「半形轉全形」雙向轉換,請參閱另一篇 JavaScript Unicode 字元寬度轉換:String.prototype.normalize NFKC 與半形全形雙向轉換。)
一、 核心複製即用範本:全形英數字與全形空白轉半形
以下函式可同時處理所有可見的全形 ASCII 符號、英文字母、數字(Unicode 範圍 \uFF01 ~ \uFF5E)以及全形空白(\u3000):
/**
* 將字串中的全形英數字、標點符號與全形空白轉換為半形
* @param {string} str - 原始輸入字串
* @returns {string} 轉換為半形後的字串
*/
const fullShapeToHalfShape = (str) => {
if (typeof str !== 'string') return '';
return str
.replace(/[\uff01-\uff5e]/g, (ch) => {
return String.fromCharCode(ch.charCodeAt(0) - 0xfee0);
})
.replace(/\u3000/g, ' ');
};
const inputStr = 'ABCDEFG 123!@#';
console.log(fullShapeToHalfShape(inputStr));
// 輸出: "ABCDEFG 123!@#"
二、 轉換原理:為什麼是減去 0xFEE0(65248)?
在 Unicode 編碼表中,半形可見 ASCII 字元與對應的全形字元之間,存在固定的線性位移差距 65248(十六進位為 0xFEE0),唯一的例外是「空白鍵」:
| 字元類型 | 半形 Unicode 編碼(十進位 / 十六進位) | 全形 Unicode 編碼(十進位 / 十六進位) | 兩者編碼差值 |
|---|---|---|---|
感嘆號(! / !) | 33 (0x0021) | 65281 (0xFF01) | 相差 65248 (0xFEE0) |
數字 0(0 / 0) | 48 (0x0030) | 65296 (0xFF10) | 相差 65248 (0xFEE0) |
大寫 A(A / A) | 65 (0x0041) | 65313 (0xFF21) | 相差 65248 (0xFEE0) |
波浪號(~ / ~) | 126 (0x007E) | 65374 (0xFF5E) | 相差 65248 (0xFEE0) |
| 空白(Space) | 32 (0x0020) | 12288 (0x3000) | 例外(需單獨替換) |
因此,只要用正規表達式 /[\uff01-\uff5e]/g 抓出落在此區間的全形字元,將其 charCodeAt(0) 減去 0xFEE0,再搭配 .replace(/\u3000/g, ' ') 將全形空白替換為半形空白即可(若要直接刪除空白,可搭配 JavaScript 去除字串前後空白、空格與換行)。
三、 僅轉換「全形數字」的精準寫法
如果在特定欄位中,您只希望把使用者輸入的「全形數字 0~9」轉成半形 0~9,而不希望動到中文全形標點符號(例如保留中文全形逗號 ,、問號 ? 與驚嘆號 !),可以將正規表達式範圍縮小至 /[\uff10-\uff19]/g:
/**
* 僅將全形數字(0-9)轉為半形數字(0-9),保留中文全形標點
*/
const fullNumberToHalf = (str) => {
return String(str).replace(/[\uff10-\uff19]/g, (ch) =>
String.fromCharCode(ch.charCodeAt(0) - 0xfee0)
);
};
console.log(fullNumberToHalf('訂單編號:12345,請確認!'));
// 輸出: "訂單編號:12345,請確認!"(全形冒號、逗號與驚嘆號皆維持原狀)
發表迴響