摘要:你真的會(huì)字符串反轉(zhuǎn)計(jì)算字符串長(zhǎng)度么字符串編碼問(wèn)題一個(gè)常見(jiàn)的問(wèn)題如何將字符串反轉(zhuǎn)一個(gè)常見(jiàn)的解答再如,如何得到一個(gè)字符串的長(zhǎng)度答這些答案都不是完全正確,或者說(shuō)并不是對(duì)于所有的字符都是適用的,例如這其中的原因涉及到了的字符串編碼。
你真的會(huì)字符串反轉(zhuǎn)、計(jì)算字符串長(zhǎng)度么? Javascript 字符串編碼 問(wèn)題
一個(gè)常見(jiàn)的問(wèn)題:如何將字符串反轉(zhuǎn)?
一個(gè)常見(jiàn)的解答:
"abcd".split("").reverse().join("") // dcba
再如,如何得到一個(gè)字符串的長(zhǎng)度?
答:
"abcd".length // 4
這些答案都不是完全正確,或者說(shuō)并不是對(duì)于所有的字符都是適用的,例如:
"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 是一套包含了人類所有的字符、編碼、展示的標(biāo)準(zhǔn)。
Unicode 對(duì)于每一個(gè)字符(character)給了唯一的數(shù)字標(biāo)示,稱為「代碼點(diǎn)」(code point)。也就是說(shuō) Unicode 利用一個(gè)抽象的數(shù)字,即 code point 來(lái)代表字符。Unicode 定義了 1,114,112 個(gè) code point,十六進(jìn)制為 0 到 10FFFF,一般的表示方式為 「U+」開(kāi)頭,后面接十六進(jìn)制表示的 code point,例如:「A」的 code point 為 U+0041。1
在實(shí)際的使用、傳輸 Unicode 中為了減少數(shù)據(jù)大小等需求,一般會(huì)將 code point 編碼(encoding)。一般的 encoding 方式為 「UCS-2」、「UTF-16」、「UTF-8」。
UCS-2:用 16 bit 來(lái)表示 code point?,F(xiàn)在 code point 的范圍已經(jīng)超越了 16 bit 可以表示的了。
UTF-16:對(duì)于可以使用 16 bit 范圍內(nèi)的 code point,就與 UCS-2 相同;否則:
code point 減 0x010000
結(jié)果前 10 bit 加 0xD800,后 10 bit 加 0xDC00
這樣就會(huì)得到兩個(gè) 16 bit 的結(jié)果,范圍分別為:0xD800 - 0xDBFF,和 0xDC00 - 0xDFFF,這兩個(gè)值就代表了相應(yīng)的 code point,一般稱這兩個(gè)值為「surrogate pairs」。
Unicode 標(biāo)準(zhǔn)保證了所有的 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 剩下的六位。
術(shù)語(yǔ)Unicode 中有很多概念需要厘清,和本文關(guān)系不大,但是對(duì)于更好的理解編碼、或者后續(xù)的更深入的學(xué)習(xí)也是有好處的。
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
例如,英語(yǔ)中的 和
一個(gè) grapheme 可以用一個(gè)或多個(gè) code point 表示,例如「?」的 code point 為 U+0063 U+0327
String.fromCodePoint(0x0063, 0x0327); // ?
多個(gè) grapheme 也可能只有一個(gè) code point 表示,例如「?」的 code point 為 U+FDFA,但是「?」是有多個(gè) grapheme 組成的。
Sting.fromCodePoint(0xFDFA); // ?
glyph:對(duì)于 grapheme 的可視化的表示。
可以看出,我們一般理解中,「字符」都是為「grapheme」;「字體」、「字號(hào)」等都是「glyph」。
原因ECMAScript 對(duì)于字符的編碼方式并沒(méi)有嚴(yán)格的約定,但是大部分引擎的實(shí)現(xiàn)都是 UTF-16,但是,Javascript 對(duì)于一個(gè)字符的定義(注意和 Unicode 中 「character」的區(qū)別):
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
,不嚴(yán)格的說(shuō)字符串就是一個(gè)個(gè) 16 bit 字符組成的串(從這個(gè)角度來(lái)說(shuō)又和 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 長(zhǎng)度大于 16 bit 的使用 UTF-16 的「surrogate pairs」即,兩個(gè) 16 bit 來(lái)表示,但同時(shí),內(nèi)部的很多處理都是按照字符(16 bit), 例如:
"a?bc".length === 5
所以就產(chǎn)生了上面字符串反轉(zhuǎn)的問(wèn)題:
String.fromCodePoint(0xD83D, 0xDCA9) ?
將 0xD83D 0xDCA9 反轉(zhuǎn)為 0xDCA9 0xD83D 導(dǎo)致錯(cuò)誤的字符串。
「a?」則是由字符「a」和一個(gè) combining marks 「 ?」組合成的一個(gè)字符:
String.fromCodePoint(0x0061, 0x0303) a?
類似的將其按照 16 bit 反轉(zhuǎn)后就會(huì)有問(wèn)題。
解答根據(jù) UTF-16 對(duì)于「surrogate pairs」的定義和 「combining marks」的 code point 位置,我們可以自己處理字符串反轉(zhuǎn)的問(wèn)題,
以「surrogate pairs」為例:
const regexSurrogatePair = /([uD800-uDBFF])([uDC00-uDFFF])/g const reverse = (string) => { return string.replace(regexSurrogatePair, ($0, $1, $2) => { return $2 + $1 // 先將「surrogate pairs」反轉(zhuǎn) }).split("").reverse().join("") } reverse("a?bc") // cb?a
更全面的庫(kù) esrever。
而對(duì)于「長(zhǎng)度」問(wèn)題:
[..."a?bc"].length // 4
或
let count = 0 for (let codePoint of "a?bc") { count++ } count // 4
因?yàn)?b>String.prototype[@@iterator]()是遍歷的 code point。
總結(jié)Javascript 字符串對(duì)外并沒(méi)有暴露 code point ,而是以 16 bit 為單位(UCS-2)提供,導(dǎo)致了 code point 長(zhǎng)度大于 16 bit 的字符(non-BMP)在某些操作上會(huì)有問(wèn)題(反轉(zhuǎn)、取長(zhǎng)度),所以在對(duì)于這種字符就需要特別處理。
文章版權(quán)歸作者所有,未經(jīng)允許請(qǐng)勿轉(zhuǎn)載,若此文章存在違規(guī)行為,您可以聯(lián)系管理員刪除。
轉(zhuǎn)載請(qǐng)注明本文地址:http://www.ezyhdfw.cn/yun/91823.html
摘要:下面代碼會(huì)存在什么問(wèn)題,如何改進(jìn)一行代碼輸出之間的所有偶數(shù)。簡(jiǎn)述進(jìn)程之間如何通信多路復(fù)用的作用模型的區(qū)別什么是并發(fā)和并行解釋什么是異步非阻塞的作用面試題說(shuō)說(shuō)你知道的命令如何查看某次提交修改的內(nèi)容答案掃碼下面的二維碼訂閱即可獲取。 引言 最近在刷面試題,所以需要看大量的 Python 相關(guān)的面試題,從大量的題目中總結(jié)了很多的知識(shí),同時(shí)也對(duì)一些題目進(jìn)行拓展了,但是在看了網(wǎng)上的大部分面試題不...
摘要:第三組長(zhǎng)度為,奇數(shù),沒(méi)有發(fā)生反轉(zhuǎn)。箭頭指示順序即為單元格填充順序。因此我們采用并查集處理朋友關(guān)系。如果沒(méi)有沖突,再把修改后的副本賦值給原并查集,添加成功否則就認(rèn)為這個(gè)添加無(wú)法進(jìn)行,原并查集對(duì)象不做修改,該請(qǐng)求為。 ...
摘要:我們有這么一個(gè)場(chǎng)景,給你一個(gè)列表,可以動(dòng)態(tài)的新增,但是最終要求列表升序,要求長(zhǎng)度小于,可以怎么做這個(gè)還不簡(jiǎn)單,幾行代碼就可以了測(cè)試驗(yàn)證上面的代碼先不考慮性能的優(yōu)化方面,有沒(méi)有問(wèn)題寫(xiě)了個(gè)簡(jiǎn)單的測(cè)試,我們來(lái)看下會(huì)出現(xiàn)什么情況啟動(dòng)參數(shù)修改 我們有這么一個(gè)場(chǎng)景,給你一個(gè)列表,可以動(dòng)態(tài)的新增,但是最終要求列表升序,要求長(zhǎng)度小于20,可以怎么做? 這個(gè)還不簡(jiǎn)單,幾行代碼就可以了 public Li...
摘要:第二個(gè)是,因?yàn)樵诘趥€(gè)位置,可以有最長(zhǎng)為的相同前后綴,依次類推。匹配時(shí)分為幾種情況字母相同,則和都加,且,因?yàn)楹缶Y匹配的長(zhǎng)度是前綴的長(zhǎng)度加。注意為了方便處理空字符串,我們?cè)诜崔D(zhuǎn)拼接的時(shí)候中間加了,這個(gè)字符要保證不會(huì)出現(xiàn)在字符串中。 Shortest Palindrome Given a string S, you are allowed to convert it to a palin...
摘要:正則表達(dá)式使用單個(gè)字符串來(lái)描述匹配一系列匹配某個(gè)句法規(guī)則的字符串。接下來(lái),是在手機(jī)正則里面已經(jīng)出現(xiàn)了。序列匹配而則匹配。分組與反向引用分組,又稱為子表達(dá)式。把正則表達(dá)式拆分成小表達(dá)式。 本文轉(zhuǎn)載自網(wǎng)絡(luò)。轉(zhuǎn)載編輯過(guò)程中,可能有遺漏或錯(cuò)誤,請(qǐng)以原文為準(zhǔn)。原文作者:水墨寒湘原文鏈接:https://juejin.im/post/582dfc... 正則表達(dá)式對(duì)于我來(lái)說(shuō)一直像黑暗魔法一樣的存...
閱讀 2045·2021-11-22 09:34
閱讀 1240·2021-10-09 09:44
閱讀 3095·2021-09-29 09:35
閱讀 3682·2021-09-14 18:01
閱讀 1562·2021-08-16 10:49
閱讀 1167·2019-08-29 14:11
閱讀 906·2019-08-29 12:47
閱讀 3135·2019-08-26 13:47