))
教程【免費下載鏈接】jstipsThis is about useful JS tips!項目地址https://gitcode.com/gh_mirrors/js/jstips點擊查看免費下載本篇是 JS Tips 系列的第 04 篇。它揭示了一個常見的國際化i18n陷阱JavaScript 原生Array.prototype.sort()只按英文字母的碼點順序排序遇到西班牙語、德語等含重音accented字符的非 ASCII 字符串時會產(chǎn)生錯序。讀完本文你將掌握使用String.prototype.localeCompare()與Intl.Collator兩種方案按語言習(xí)慣正確排序的方法并能針對不同區(qū)域locale定制排序規(guī)則避免線上數(shù)據(jù)出現(xiàn)意外的排列結(jié)果。問題原生sort()在非 ASCII 字符串上的錯序JavaScript 原生提供了Array.prototype.sort()方法用于排序數(shù)組。當(dāng)不傳入比較函數(shù)時sort()會把每個數(shù)組元素當(dāng)作字符串并按字母表順序排序[Shanghai, New York, Mumbai, Buenos Aires].sort(); // [Buenos Aires, Mumbai, New York, Shanghai]對純英文ASCII字符串這個結(jié)果是符合預(yù)期的。但當(dāng)你嘗試排序一個包含非 ASCII 字符如重音字母é、á、ú的數(shù)組時就會得到一個奇怪的結(jié)果[é, a, ú, c].sort(); // [c, e, á, ú] // 錯序不符合任何自然語言的字母順序再看兩個真實的語言場景// 西班牙語 [único,árbol, cosas, fútbol].sort(); // [cosas, fútbol, árbol, único] // 錯誤順序 // 德語 [Woche, w?chentlich, w?re, Wann].sort(); // [Wann, Woche, w?re, w?chentlich] // 錯誤順序在西班牙語中árbol應(yīng)排在cosas之前在德語中Wann應(yīng)排在w?re之前、w?chentlich之前。但原生排序完全打亂了語言習(xí)慣。為什么會這樣從語言規(guī)范與實現(xiàn)機制可以推斷不帶比較函數(shù)調(diào)用sort()時引擎會把每個元素轉(zhuǎn)換為字符串然后逐字符按 UTF-16 碼元code unit的數(shù)值大小比較。重音字母的 Unicode 碼點遠(yuǎn)大于普通 ASCII 字母例如é的碼點是 U00E9大于a的 U0061 和c的 U0063于是é、á、ú這類字符全部被排到了a、c之后看起來就是亂序。簡單說原生sort()只懂英文或者說只懂純碼點排序不理解任何語言的重音規(guī)則、大小寫規(guī)則與字母擴展規(guī)則。解決方案一使用String.prototype.localeCompare()localeCompare()是字符串實例上的方法由 ECMAScript 國際化 APIECMA-402提供。它按指定區(qū)域的語言規(guī)則比較兩個字符串返回一個負(fù)數(shù)、零或正數(shù)正好可以作為sort()的比較函數(shù)[único,árbol, cosas, fútbol].sort(function (a, b) { return a.localeCompare(b); }); // [árbol, cosas, fútbol, único] [Woche, w?chentlich, w?re, Wann].sort(function (a, b) { return a.localeCompare(b); }); // [Wann, w?re, Woche, w?chentlich]可以看到兩組數(shù)據(jù)都恢復(fù)了正確的語言排序árbol排到了最前Wann也排到了德語序列的正確位置。解決方案二使用Intl.CollatorIntl.Collator是同一個國際化 API 提供的更專門的排序器對象。它的compare屬性是一個可直接傳入sort()的穩(wěn)定比較函數(shù)寫法更簡潔[único,árbol, cosas, fútbol].sort(Intl.Collator().compare); // [árbol, cosas, fútbol, único] [Woche, w?chentlich, w?re, Wann].sort(Intl.Collator().compare); // [Wann, w?re, Woche, w?chentlich]輸出與localeCompare()完全一致但省去了每次比較時臨時創(chuàng)建函數(shù)調(diào)用的開銷。定制區(qū)域locale與比較規(guī)則這兩種方法都帶有各自的可配置參數(shù)以便適配不同的語言環(huán)境。兩個 API 都接受locales與options兩個參數(shù)這是它們最實用的部分locales區(qū)域標(biāo)識例如es西班牙語、de德語、fr法語、zh-Hans-CN簡體中文。不傳時使用運行環(huán)境的默認(rèn)區(qū)域。// 指定西班牙語區(qū)域排序 [único, árbol, cosas, fútbol] .sort((a, b) a.localeCompare(b, es)); // 用 Collator 指定德語區(qū)域 const germanCollator new Intl.Collator(de); [Woche, w?chentlich, w?re, Wann].sort(germanCollator.compare);options比較規(guī)則常用配置包括sensitivity決定比較時是否區(qū)分大小寫與重音取值如base、accent、case、variant和usage取值sort或search等。例如sensitivity: base意味著忽略大小寫與重音差異只按基本字母比較// 忽略大小寫與重音進行排序 [é, E, e, a, A].sort((a, b) a.localeCompare(b, fr, { sensitivity: base }));這兩組參數(shù)讓localeCompare()與Intl.Collator不僅能正確排序還能按業(yè)務(wù)需求調(diào)整排序到多細(xì)的粒度。性能考量大批量字符串優(yōu)先使用Intl.Collator根據(jù)原文檔引述的官方性能說明當(dāng)需要比較大量字符串時Intl.Collator更快。原因從實現(xiàn)結(jié)構(gòu)上可以理解Collator是一個可復(fù)用的排序器對象其compare函數(shù)被一次性構(gòu)建后反復(fù)調(diào)用而localeCompare每次調(diào)用都可能重新解析區(qū)域規(guī)則。因此排序少量數(shù)據(jù)如幾個下拉選項兩者皆可localeCompare寫法直觀排序成百上千條字符串如用戶列表、商品名、城市列表優(yōu)先創(chuàng)建一次Intl.Collator并復(fù)用其compare能明顯減少重復(fù)開銷。綜合實戰(zhàn)去重 按語言排序的完整示例本倉庫的另一篇 JS Tips第 26 篇過濾并排序字符串列表演示了先filter去重、再sort排序的組合用法。把兩者結(jié)合并換成localeCompare/Intl.Collator作為比較器就是一個處理多語言數(shù)據(jù)列表的完整方案const names [úrsula, álvaro, carlos, úrsula, érika, álvaro]; // ES6 寫法去重后按西班牙語規(guī)則排序 const sorted [...new Set(names)] .sort((a, b) a.localeCompare(b, es)); console.log(sorted); // [álvaro, álvaro, carlos, érika, úrsula]順序按區(qū)域規(guī)則確定再進一步用Intl.Collator預(yù)構(gòu)建比較器適合數(shù)據(jù)量大、需要反復(fù)排序的場景const collator new Intl.Collator(es); const sorted [...new Set(names)].sort(collator.compare);倉庫內(nèi)的印證與擴展閱讀本文對應(yīng)的原始文檔英文原版另有簡體中文、繁體中文、西班牙語等多語言版本可對照閱讀README.md 的 Tips 列表將本篇列為第 04 號技巧同系列的排序/過濾主題還可參考第 26 篇過濾與排序字符串列表若想進一步掌握字符串包含判斷可閱讀第 15 篇indexOf 的簡化用法其中也涉及字符串比較的邊界場景帖子格式規(guī)范參見 POST_TEMPLATE.md。小結(jié)當(dāng)你要排序的字符串?dāng)?shù)組并非純英文時務(wù)必不要直接使用裸的array.sort()小數(shù)據(jù)量使用a.localeCompare(b)必要時傳入locales與options大數(shù)據(jù)量預(yù)構(gòu)建Intl.Collator并復(fù)用其compare性能更優(yōu)多語言產(chǎn)品為每種目標(biāo)語言顯式指定區(qū)域標(biāo)識避免依賴運行環(huán)境的默認(rèn)區(qū)域?qū)е陆Y(jié)果不一致。記住這條經(jīng)驗排序含重音字符的字符串時使用localeCompare()或Intl.Collator才能得到符合語言習(xí)慣的排列結(jié)果。贊分享教程【免費下載鏈接】jstipsThis is about useful JS tips!項目地址https://gitcode.com/gh_mirrors/js/jstips點擊查看免費下載相關(guān)推薦jstips 實戰(zhàn) 04帶重音符號字符串的正確排序——localeCompare 與 Intl.Collator 全面解析jstips 實戰(zhàn) 04帶重音符號字符串的正確排序——localeCompare 與 Intl.Collator 全面解析 本文是 jstips 倉庫第 04教程jstips 實戰(zhàn) 04帶重音符號的字符串排序——localeCompare 與 Intl.Collator 完全指南jstips 實戰(zhàn) 04帶重音符號的字符串排序——localeCompare 與 Intl.Collator 完全指南 本文源自 jstips https:/教程TypeScript 類型挑戰(zhàn)用 Union 與模板字符串實現(xiàn) CheckRepeatedChars判斷字符串是否含重復(fù)字符TypeScript 類型挑戰(zhàn)用 Union 與模板字符串實現(xiàn) CheckRepeatedChars判斷字符串是否含重復(fù)字符 導(dǎo)讀 本篇文章圍繞 type示例工程創(chuàng)作聲明:本文部分內(nèi)容由AI輔助生成(AIGC),僅供參考