摘要:你真的會字符串反轉計算字符串長度么字符串編碼問題一個常見的問題如何將字符串反轉一個常見的解答再如,如何得到一個字符串的長度答這些答案都不是完全正確,或者說并不是對于所有的字符都是適用的,例如這其中的原因涉及到了的字符串編碼。
你真的會字符串反轉、計算字符串長度么? Javascript 字符串編碼 問題
一個常見的問題:如何將字符串反轉?
一個常見的解答:
"abcd".split("").reverse().join("") // dcba
再如,如何得到一個字符串的長度?
答:
"abcd".length // 4
這些答案都不是完全正確,或者說并不是對于所有的字符都是適用的,例如:
"a?bc".split("").reverse().join("") cb??a "a?bc".lenght // 5 "aa?bc".split("").reverse().join("") cb?aa "aa?bc".length // 5
這其中的原因涉及到了 Javascript 的字符串編碼。
Unicode 及編碼Unicode 是一套包含了人類所有的字符、編碼、展示的標準。
Unicode 對于每一個字符(character)給了唯一的數字標示,稱為「代碼點」(code point)。也就是說 Unicode 利用一個抽象的數字,即 code point 來代表字符。Unicode 定義了 1,114,112 個 code point,十六進制為 0 到 10FFFF,一般的表示方式為 「U+」開頭,后面接十六進制表示的 code point,例如:「A」的 code point 為 U+0041。1
在實際的使用、傳輸 Unicode 中為了減少數據大小等需求,一般會將 code point 編碼(encoding)。一般的 encoding 方式為 「UCS-2」、「UTF-16」、「UTF-8」。
UCS-2:用 16 bit 來表示 code point?,F在 code point 的范圍已經超越了 16 bit 可以表示的了。
UTF-16:對于可以使用 16 bit 范圍內的 code point,就與 UCS-2 相同;否則:
code point 減 0x010000
結果前 10 bit 加 0xD800,后 10 bit 加 0xDC00
這樣就會得到兩個 16 bit 的結果,范圍分別為:0xD800 - 0xDBFF,和 0xDC00 - 0xDFFF,這兩個值就代表了相應的 code point,一般稱這兩個值為「surrogate pairs」。
Unicode 標準保證了所有的 code point 都可以用 UTF-16 表示。
UTF-8:
code point 小于 0x7F,則編碼為其本身。
code point 大于 0x7F 小于 0x7FF,編碼為 110+code point 前五位,10+code point 剩下的。
code point 大于 0x7FF 小于 0xFFFF,編碼為 1110+code point 前四位,10+code point 剩下的。
剩下的 code point 編碼為 11110+code point 前三位,10+code point 剩下的六位。
術語Unicode 中有很多概念需要厘清,和本文關系不大,但是對于更好的理解編碼、或者后續的更深入的學習也是有好處的。
character:
The smallest component of written language that has semantic value; refers to the abstract meaning and/or shape, rather than a specific shape (see also glyph), though in code tables some form of visual representation is essential for the reader’s understanding. 。
grapheme:
A minimally distinctive unit of writing in the context of a particular writing system
例如,英語中的 和
一個 grapheme 可以用一個或多個 code point 表示,例如「?」的 code point 為 U+0063 U+0327
String.fromCodePoint(0x0063, 0x0327); // ?
多個 grapheme 也可能只有一個 code point 表示,例如「?」的 code point 為 U+FDFA,但是「?」是有多個 grapheme 組成的。
Sting.fromCodePoint(0xFDFA); // ?
glyph:對于 grapheme 的可視化的表示。
可以看出,我們一般理解中,「字符」都是為「grapheme」;「字體」、「字號」等都是「glyph」。
原因ECMAScript 對于字符的編碼方式并沒有嚴格的約定,但是大部分引擎的實現都是 UTF-16,但是,Javascript 對于一個字符的定義(注意和 Unicode 中 「character」的區別):
the word “character” will be used to refer to a 16-bit unsigned value used to represent a single 16-bit unit of text 2
,不嚴格的說字符串就是一個個 16 bit 字符組成的串(從這個角度來說又和 UCS-2 很相似),也稱為(code units)。
"a?bc"[0] // a "a?bc"[1] // ? "a?bc"[2] // ? "a?bc"[3] // b "a?bc"[4] // c "aa?bc"[0] // a "aa?bc"[1] // a "aa?bc"[2] // ? "aa?bc"[3] // b "aa?bc"[4] // c
「?」的 code point 長度大于 16 bit 的使用 UTF-16 的「surrogate pairs」即,兩個 16 bit 來表示,但同時,內部的很多處理都是按照字符(16 bit), 例如:
"a?bc".length === 5
所以就產生了上面字符串反轉的問題:
String.fromCodePoint(0xD83D, 0xDCA9) ?
將 0xD83D 0xDCA9 反轉為 0xDCA9 0xD83D 導致錯誤的字符串。
「a?」則是由字符「a」和一個 combining marks 「 ?」組合成的一個字符:
String.fromCodePoint(0x0061, 0x0303) a?
類似的將其按照 16 bit 反轉后就會有問題。
解答根據 UTF-16 對于「surrogate pairs」的定義和 「combining marks」的 code point 位置,我們可以自己處理字符串反轉的問題,
以「surrogate pairs」為例:
const regexSurrogatePair = /([uD800-uDBFF])([uDC00-uDFFF])/g const reverse = (string) => { return string.replace(regexSurrogatePair, ($0, $1, $2) => { return $2 + $1 // 先將「surrogate pairs」反轉 }).split("").reverse().join("") } reverse("a?bc") // cb?a
更全面的庫 esrever。
而對于「長度」問題:
[..."a?bc"].length // 4
或
let count = 0 for (let codePoint of "a?bc") { count++ } count // 4
因為String.prototype[@@iterator]()是遍歷的 code point。
總結Javascript 字符串對外并沒有暴露 code point ,而是以 16 bit 為單位(UCS-2)提供,導致了 code point 長度大于 16 bit 的字符(non-BMP)在某些操作上會有問題(反轉、取長度),所以在對于這種字符就需要特別處理。
文章版權歸作者所有,未經允許請勿轉載,若此文章存在違規行為,您可以聯系管理員刪除。
轉載請注明本文地址:http://specialneedsforspecialkids.com/yun/91823.html
摘要:下面代碼會存在什么問題,如何改進一行代碼輸出之間的所有偶數。簡述進程之間如何通信多路復用的作用模型的區別什么是并發和并行解釋什么是異步非阻塞的作用面試題說說你知道的命令如何查看某次提交修改的內容答案掃碼下面的二維碼訂閱即可獲取。 引言 最近在刷面試題,所以需要看大量的 Python 相關的面試題,從大量的題目中總結了很多的知識,同時也對一些題目進行拓展了,但是在看了網上的大部分面試題不...
摘要:第三組長度為,奇數,沒有發生反轉。箭頭指示順序即為單元格填充順序。因此我們采用并查集處理朋友關系。如果沒有沖突,再把修改后的副本賦值給原并查集,添加成功否則就認為這個添加無法進行,原并查集對象不做修改,該請求為。 ...
摘要:我們有這么一個場景,給你一個列表,可以動態的新增,但是最終要求列表升序,要求長度小于,可以怎么做這個還不簡單,幾行代碼就可以了測試驗證上面的代碼先不考慮性能的優化方面,有沒有問題寫了個簡單的測試,我們來看下會出現什么情況啟動參數修改 我們有這么一個場景,給你一個列表,可以動態的新增,但是最終要求列表升序,要求長度小于20,可以怎么做? 這個還不簡單,幾行代碼就可以了 public Li...
摘要:第二個是,因為在第個位置,可以有最長為的相同前后綴,依次類推。匹配時分為幾種情況字母相同,則和都加,且,因為后綴匹配的長度是前綴的長度加。注意為了方便處理空字符串,我們在反轉拼接的時候中間加了,這個字符要保證不會出現在字符串中。 Shortest Palindrome Given a string S, you are allowed to convert it to a palin...
摘要:正則表達式使用單個字符串來描述匹配一系列匹配某個句法規則的字符串。接下來,是在手機正則里面已經出現了。序列匹配而則匹配。分組與反向引用分組,又稱為子表達式。把正則表達式拆分成小表達式。 本文轉載自網絡。轉載編輯過程中,可能有遺漏或錯誤,請以原文為準。原文作者:水墨寒湘原文鏈接:https://juejin.im/post/582dfc... 正則表達式對于我來說一直像黑暗魔法一樣的存...
閱讀 1868·2021-11-22 09:34
閱讀 1141·2021-10-09 09:44
閱讀 3001·2021-09-29 09:35
閱讀 3617·2021-09-14 18:01
閱讀 1465·2021-08-16 10:49
閱讀 1084·2019-08-29 14:11
閱讀 849·2019-08-29 12:47
閱讀 3068·2019-08-26 13:47