紀錄工作經驗、相關知識,解決技術相關問題。

Javascript, React, 網站相關

[JS] 字串將每個字逐一拆解成陣列(字串轉陣列):split、展開運算子與 Array.from 比較

[JS] 字串將每個字逐一拆解成陣列(字串轉陣列):split、展開運算子與 Array.from 比較 特色圖片

在 JavaScript 開發中,我們常會需要將一個字串裡的每個字逐一拆解成陣列(字串轉陣列),例如輸入字串 'qqqeee',希望能自動拆解並輸出成陣列 ['q', 'q', 'q', 'e', 'e', 'e'] 以利後續執行 .map()、.filter() 或字數統計。本篇整理 4 種常見的 JavaScript 字串轉陣列寫法,並說明在處理中英文字元與 Emoji 表情符號時的差異。

一、基礎做法:使用 String.prototype.split('')

如果確定輸入的字串只包含一般英數字元、標點符號或常見繁體中文字(基本多文種平面 BMP 字元),最直覺的做法是使用字串內建的 .split('') 方法,並將分隔符號指定為空字串 ''。這樣就會將每個字元拆解成獨立的子字串,最終回傳所需的陣列:

function splitStringToArray(inputString) {
  return inputString.split('');
}

// 測試一般英數字串
const input = 'qqqeee';
const output = splitStringToArray(input);
console.log(output);
// 輸出: ['q', 'q', 'q', 'e', 'e', 'e']

// 測試繁體中文字串
console.log('前端開發'.split(''));
// 輸出: ['前', '端', '開', '發']

二、進階做法:解決 Emoji 亂碼的 [...str] 與 Array.from()

雖然 split('') 簡單好用,但它是以 UTF-16 編碼單元(Code Unit) 為單位進行切割。當使用者輸入的字串包含 Emoji 表情符號(例如 😂 或 🚀)或罕見漢字時,因為這些字元在 UTF-16 中是由兩個代理配對(Surrogate Pair)組成,split('') 會把同一個 Emoji 硬生生切成兩半變成亂碼!

此時改用 ES6 的**展開運算子(Spread Operator [...str])**或 Array.from(str),就會改依循字串的可迭代協定(依 Unicode Code Point 碼點)正確拆解:

const textWithEmoji = 'Hi😂👍';

// ❌ 使用 split('') 會把 Emoji 拆成兩個無效的 UTF-16 代理字元
console.log(textWithEmoji.split(''));
// 輸出: ['H', 'i', '\uD83D', '\uDE02', '\uD83D', '\uDC4D'] (出現亂碼)

// ✅ 方法 2:使用 ES6 展開運算子 [...str]
console.log([...textWithEmoji]);
// 輸出: ['H', 'i', '😂', '👍']

// ✅ 方法 3:使用 Array.from(),還可同時傳入第二個參數對每個字元做轉換
const charCodes = Array.from('abc', (char) => char.toUpperCase());
console.log(charCodes);
// 輸出: ['A', 'B', 'C']

三、處理複合型 Emoji(ZWJ 序列):使用 Intl.Segmenter

如果專案需要處理更複雜的「複合型 Emoji」(例如家庭符號 👨‍👩‍👧‍👦 或帶膚色修飾的圖示,底層是由多個 Emoji 透過零寬連字元 ZWJ 組合而成),連 [...str] 也會將它拆成 4 個獨立人頭。這時可以使用現代瀏覽器與 Node.js 原生內建的 Intl.Segmenter 依「視覺字素叢集(Grapheme Cluster)」精準拆解:

function splitByGrapheme(str) {
  const segmenter = new Intl.Segmenter('zh-TW', { granularity: 'grapheme' });
  return Array.from(segmenter.segment(str), (item) => item.segment);
}

const familyEmoji = 'A👨‍👩‍👧‍👦B';

console.log([...familyEmoji]);
// 輸出: ['A', '👨', '‍', '👩', '‍', '👧', '‍', '👦', 'B'] (被拆散)

console.log(splitByGrapheme(familyEmoji));
// 輸出: ['A', '👨‍👩‍👧‍👦', 'B'] (完整保留每個視覺字元)

四、JavaScript 4 種字串轉陣列方法比較表

轉換方法語法範例一般 Emoji (😂)適用情境說明
str.split('')'abc'.split('')❌ 會拆壞成亂碼純英數、ASCII 程式碼、一般中文字串快速拆解
展開運算子 [...str][...'abc']✅ 正常保留現代專案最推薦的簡潔寫法,可安全處理常見 Emoji
Array.from(str)Array.from('abc', fn)✅ 正常保留拆解字串的同時,需要立刻對每個字元執行映射轉換(Map)
Intl.Segmentersegmenter.segment(str)✅ 支援複合 Emoji聊天室、社群輸入框等需精準計算人類視覺字數的場景

💡 延伸閱讀:將字串拆解成陣列後,若要在 React 中透過 .map() 渲染成畫面元素,務必注意每個子元素的 key 設定,可參考站內另一篇 Encountered Two Children with the Same Key – React Console Warning 原因與唯一 Key 解法;若是要解析網址字串,則可參考 JS 解析 URL:new URL 與 URLSearchParams 屬性對照。

參考資料與延伸閱讀

發佈留言