專案裡有個 AngularJS 畫面,scope.datalist 每筆資料的欄位開頭儲存著 (一)、(二)、(十)、(二十) 這類中文數字前綴。Array.sort 預設按 Unicode 碼位排,(一) 排在 (三) 前面沒問題,但 (十) 和 (二十) 的字元碼比個位數字大,順序就全亂了。
下面這個 customSort 把中文數字轉成阿拉伯數字再比較,支援一到九十九,沒有前綴的項目自動排到最後。
欄位名稱說明: 範例中的
Catacory是原始資料庫欄位名稱(歷史拼錯沿用至今),不是 typo 建議,直接抄用時請換成你自己的欄位名。
完整程式碼
1 | const getNumber = (str) => { |
邏輯拆解
正則抓取前綴
1 | str.match(/^\(([一二三四五六七八九十]+)\)/) |
^ 確保從字串開頭比對;\( \) 匹配全形括號的半形版本(即 ASCII 括號);中間的捕獲群組取出純漢字部分,丟給後面的轉換邏輯。
中文數字轉阿拉伯數字
三條路徑,覆蓋一到九十九:
| 輸入 | 路徑 | 計算 | 結果 |
|---|---|---|---|
| 一、二…九 | 長度 1 | numMap[numStr] |
1–9 |
| 十 | 長度 1 → numMap['十'] |
numMap['十'] = 10 |
10 |
| 十一…十九 | 以「十」開頭,長度 2 | 10 + numMap[numStr[1]] |
11–19 |
| 二十…九十 | 其他,長度 2 | numMap[numStr[0]] * 10 + 0 |
20–90 |
| 二十一…九十九 | 其他,長度 3 | numMap[numStr[0]] * 10 + numMap[numStr[2]] |
21–99 |
注意 numStr[2] 取的是第三個字元(索引從 0 起算),「二十一」的索引 2 剛好是「一」,正確。若欄位有超過九十九的情況,這個函式無法處理,需要另外擴充。
null / undefined 防禦
原版沒有防禦,str.match() 收到 null 或 undefined 直接拋 TypeError。加一行:
1 | if (!str) return 100; |
讓缺值資料和無前綴資料一樣排到最後,不會 crash。
無前綴項目排到最後
1 | if (!match) return 100; |
100 大於所有可能的中文數字轉換結果(最大 99),確保沒有括號前綴的資料落在排序尾端。
回傳 0 與 AngularJS / IE11
aNum === bNum 時回傳 0,依賴排序演算法的穩定性維持原始相對順序。ES2019 之後 JavaScript 規範明確要求穩定排序,現代瀏覽器和 Node.js 11+ 都符合。
不過 scope.datalist 暗示 AngularJS 場景,若仍需支援 IE11,IE11 的 Array.sort 不保證穩定。這種情況要麼在 return 0 前加索引比較當 tie-breaker,要麼確認已脫離 IE11 支援需求再沿用現有寫法。





