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