日韩性视频-久久久蜜桃-www中文字幕-在线中文字幕av-亚洲欧美一区二区三区四区-撸久久-香蕉视频一区-久久无码精品丰满人妻-国产高潮av-激情福利社-日韩av网址大全-国产精品久久999-日本五十路在线-性欧美在线-久久99精品波多结衣一区-男女午夜免费视频-黑人极品ⅴideos精品欧美棵-人人妻人人澡人人爽精品欧美一区-日韩一区在线看-欧美a级在线免费观看

歡迎訪問(wèn) 生活随笔!

生活随笔

當(dāng)前位置: 首頁(yè) > 运维知识 > 数据库 >内容正文

数据库

json mysql乱码问题_JSON数据乱码问题

發(fā)布時(shí)間:2024/10/14 数据库 69 豆豆
生活随笔 收集整理的這篇文章主要介紹了 json mysql乱码问题_JSON数据乱码问题 小編覺(jué)得挺不錯(cuò)的,現(xiàn)在分享給大家,幫大家做個(gè)參考.

背景

程序員一提到編碼應(yīng)該都不陌生,像gbk、utf-8、ascii等這些編碼更是經(jīng)常在用,但時(shí)不時(shí)也會(huì)出個(gè)亂碼問(wèn)題,解決這個(gè)問(wèn)題的方法大部分都是先google和baidu一下,最后可能在某個(gè)犄角旮旯里找到一點(diǎn)信息,然后就機(jī)械的按部就班的模仿下來(lái),結(jié)果問(wèn)題可能真就迎刃而解了,然后就草草了事,下回遇到相似的問(wèn)題,可能又是重復(fù)上面的過(guò)程。很少有人有耐心去花精力弄明白這寫(xiě)問(wèn)題的根本原因,以及解決這些問(wèn)題的原理是什么。這篇文章就是通過(guò)一個(gè)實(shí)際案例,試著去講清楚什么是編碼,亂碼又是怎么產(chǎn)生的,以及如何解決。該案例是從lua_cjson.c這個(gè)庫(kù)開(kāi)始的,對(duì)這個(gè)庫(kù)不熟悉也沒(méi)關(guān)系,也不需要熟悉它,我們只是借用它來(lái)說(shuō)明亂碼問(wèn)題,只需要跟著文章的思路走就可以。

前段時(shí)間同事在作一個(gè)新項(xiàng)目的時(shí)候用到了lua_cjson.c這個(gè)庫(kù)(以下簡(jiǎn)稱(chēng)cjson),將json串轉(zhuǎn)換成LUA本地的數(shù)據(jù)結(jié)構(gòu),但是在使用的過(guò)程中出現(xiàn)了中文亂碼問(wèn)題,奇怪的是只有那么幾個(gè)字是亂碼,這其中就包括”朶”字,其他字一切正常。經(jīng)了解json串用的是GBK編碼,那問(wèn)題就來(lái)了,為什么用gbk編碼會(huì)出現(xiàn)這個(gè)問(wèn)題,原因是什么?又應(yīng)該怎么解決這個(gè)問(wèn)題?

要解釋清楚這個(gè)問(wèn)題,首先我們來(lái)看看json串都有哪些要求。

JSON規(guī)范

json全稱(chēng)JavaScript Object Notion是結(jié)構(gòu)化數(shù)據(jù)序列化的一個(gè)文本,可以描述四種基本類(lèi)型(strings,numbers,booleans and null)和兩種結(jié)構(gòu)類(lèi)型(objects and arrays)。

RFC4627中有這樣一段話(huà)

A string is a sequence of zero or more Unicode characters.

字符串有零個(gè)或多個(gè)unicode字符序列組成.

在這里稍微解釋下什么是unicode字符。我們都知道ascii字符有字母、數(shù)字等,但是他收錄的字只有一百多個(gè)。比如漢字就不是ascii字符,但是unicode收錄了漢字,所以漢字可以是unicode字符。這里要說(shuō)明的是unicode字符其實(shí)就是一些符號(hào)。

現(xiàn)在另一個(gè)問(wèn)題出來(lái)了,在json文本中應(yīng)該怎么表示這些字符。

在規(guī)范的Encoding片段是這樣說(shuō)的

JSON text SHALL be encoded in Unicode. The default encoding is UTF-8。

JSON文本SHALL把unicode字符編碼。默認(rèn)使用utf-8編碼。

我們看到在這里用到了SHALL[RFC2119]這個(gè)關(guān)鍵字,也就是說(shuō)字符必須被編碼后才能作為JSON串使用。而且默認(rèn)使用utf-8編碼。

如何判斷使用的是那種unicode編碼呢?

Since the first two characters of a JSON text will always be ASCII characters[RFC0020],

it is possible to determine whether an octet stream is UTF-8、UTF-16(BE or LE), or

UTF-32(BE or LE)by looking at the pattern of nulls in the first four octets.

由于json文本的前兩個(gè)字符(注意這里說(shuō)的是字符,不是字節(jié))一定是ASCII字符,因此可以從一個(gè)字節(jié)

流的前四個(gè)字節(jié)(注意是字節(jié))中判斷出該字節(jié)流是UTF-8、UTF-16(BE or LE)、or UTF-32(BE or LE)編碼。

00 00 00 xx UTF-32BE? (u32編碼大端)

xx 00 00 00 UTF-32LE? (u32編碼小端)

00 xx 00 xx UTF-16BE? (u16編碼大端)

xx 00 xx 00 UTF-16LE? (u16編碼小端)

xx xx xx xx UTF-8 ? (utf-8編碼)

ps:

u32用32位的4字節(jié)整數(shù)表示一個(gè)字符;

u16用16位的2字節(jié)整數(shù)表示一個(gè)字符,如果2字節(jié)表示不了,就用連續(xù)兩個(gè)16位的2字節(jié)整

數(shù)表示,所以就會(huì)出現(xiàn)u16編碼中有4個(gè)字節(jié)表示一個(gè)字符的情況,和u32的四字節(jié)不一

樣的是,該字符在u16中的前兩個(gè)字節(jié)和后兩個(gè)字節(jié)之間不會(huì)有字序的問(wèn)題。

utf-8用多個(gè)8位的1字節(jié)序列來(lái)表示一個(gè)字符,所以沒(méi)有字序的問(wèn)題.

截止到現(xiàn)在我們沒(méi)有看到任何關(guān)于可以使用GBK編碼的信息,難道json文本就不能用gbk編碼嗎,如果真的不能用的話(huà),那為什么cjson不是把所有的gbk編碼解釋稱(chēng)亂碼,而是只有某幾個(gè)字是亂碼.

在規(guī)范中對(duì)json解析器有這樣一段描述:

A JSON parser transforms a JSON text into another representation.

A JSON parser MUST accept all texts that conform to the JSON grammar.

A JSON parser MAY accept non-JSON forms or extensions.

json解析器可以將一個(gè)json文本轉(zhuǎn)換成其他表示方式。

json解析器MUST接受所有符合json語(yǔ)法的文本.

json解析器MAY接受非json形式或擴(kuò)展的文本.

亂碼的原因

從規(guī)范對(duì)對(duì)解析器的描述可以看到,規(guī)范并沒(méi)有要求解析器必須對(duì)文本的編碼方式做校驗(yàn),而且解析器也可以有選擇的去接受非json形式的文本。

現(xiàn)在我們?cè)賮?lái)看看cjson解析器是如何做的,在cjson開(kāi)頭的注釋中說(shuō)了這么一句話(huà):

Invalid UTF-8 characters are not detected and will be passed untouched。

If required, UTF-8 error checking should be done outside this library。

發(fā)現(xiàn)無(wú)效的UTF-8編碼會(huì)直接放過(guò),如果有必要對(duì)UTF-8編碼的檢查應(yīng)該在該庫(kù)的之外。

說(shuō)的很清楚,對(duì)非utf8編碼直接放過(guò),不做任何檢查,所以用gbk編碼不符合規(guī)范,但又可以被解析的答案就出來(lái)了。那”朶”等這些字的亂碼問(wèn)題又是怎么回事? 我們現(xiàn)在看看cjson對(duì)規(guī)范中的另外兩個(gè)編碼utf16、utf32是如何做的,然后再說(shuō)亂碼問(wèn)題.

在cjson解析方法的開(kāi)始處是這么做的:

/* Detect Unicode other than UTF-8(see RFC 4627, Sec 3)

*

* CJSON can support any simple data type, hence only the first

* character is guaranteed to be ASCII (at worst:'"'). This is

* still enough to detect whether the wrong encoding is in use.

*/

if (json_len >=2 && (!json.data[0] || !json.data[1]))

luaL_error(1,"JSON parser does not support UTF-16 or UTF-32");

前面我們說(shuō)過(guò)一個(gè)json串的前兩個(gè)字符一定是ascii字符,也就是說(shuō)一個(gè)json串至少也的有兩個(gè)字節(jié).所以這段代碼首先判斷json串的長(zhǎng)度是不是大于等2,然后根據(jù)串的前兩個(gè)字節(jié)的值,是否有零來(lái)判斷該文本是否是非utf-8編碼。結(jié)果已經(jīng)看到了,人家不支持規(guī)范上說(shuō)的u16和u32編碼.

現(xiàn)在我們就來(lái)看看”朶”這個(gè)子是如何變成亂碼的,經(jīng)過(guò)對(duì)cjson源碼的分析得知,cjson在處理字節(jié)流的時(shí)候當(dāng)遇見(jiàn)’\’反斜杠時(shí)會(huì)猜測(cè)后一個(gè)字節(jié)應(yīng)該是要被轉(zhuǎn)義的字符,比如\b、\r之類(lèi)的字符,如果是就放行,如果不是,cjson就認(rèn)為這不是一個(gè)正確的json格式,就會(huì)把這個(gè)字節(jié)給干掉,所以本來(lái)用兩個(gè)字節(jié)表示的漢子就硬生生的給掰彎了。

那”朶”字跟’\’反斜杠又有什么關(guān)系? 查詢(xún)這兩字符在編碼中的表示得出:

“朶” 0x965C

“\” 0x5C

這樣我們就看到”朶”字的低位字節(jié)和”\”字符相同,都是0x5C,如果這時(shí)候”朶”字后邊不是b、r之類(lèi)的可以被轉(zhuǎn)移ascii字符,cjson就會(huì)把這個(gè)字節(jié)和緊跟其后的一個(gè)字節(jié)抹掉,所以亂碼就產(chǎn)生了。

那我們應(yīng)該怎么解決這個(gè)問(wèn)題,讓cjson可以順利的支持gbk編碼呢,首先我們看看gbk編碼是怎么回事,為什么會(huì)出現(xiàn)低位字節(jié)和ascii沖突的問(wèn)題.

GB_編碼系列

先來(lái)了解一下GB系列的編碼范圍問(wèn)題:

GB2312(1980)共收錄7445個(gè)字符,6763個(gè)漢字和682個(gè)其他字符。

每個(gè)漢字及符號(hào)用兩個(gè)字節(jié)表示,為了跟ascii兼容,處理程序使用EUC存儲(chǔ)方法。

漢字的編碼范圍

高字節(jié): 0xB0 – 0xF7,

低字節(jié): 0xA1 – 0xFE,

占用72*94=6768,0xD7FA – 0xD7FE未使用。

GBK共收錄21886個(gè)字符,采用一字節(jié)和雙字節(jié)編碼。

單字節(jié)表示范圍

8位: 0x0 – 0x7F

雙字節(jié)表示范圍

高字節(jié): 0x81 – 0xFE

低字節(jié): 0x40 – 0x7E、0x80 – 0xFE

GB18030收錄70244個(gè)漢字,采用1、2、4字節(jié)編碼。

單字節(jié)范圍

8位: 0x0 – 0x7F

雙字節(jié)范圍

高字節(jié): 0x81 – 0xFE

低字節(jié): 0x40 – 0xFE

四字節(jié)范圍

第一字節(jié):0x81 – 0xFE

第二字節(jié):0x30 – 0x39

第三字節(jié):0x81 – 0xFE

第四字節(jié):0x30 – 0x39

由于GB類(lèi)的編碼都是向下兼容的,這里就有一個(gè)問(wèn)題,因?yàn)镚B2312的兩個(gè)字節(jié)的高位都是1,符合這個(gè)條件的碼位只有128*128=16384個(gè)。GBK和GB18030都大于這個(gè)數(shù),所以為了兼容,我們從上面的編碼范圍看到,這兩個(gè)編碼都用到了低位字節(jié)的最高位可以為0的情況。

最終得出的結(jié)論就是,在GBK編碼中只要該字符是兩個(gè)字節(jié)表示,并且低位字節(jié)是0x5C的字符都會(huì)被cjson弄成亂碼.

解決方案:

1) 不要使用gbk編碼,將你的字符串轉(zhuǎn)換成utf-8編碼.

2) 對(duì)cjson源碼稍微做個(gè)改動(dòng),就是在每個(gè)字節(jié)到來(lái)之前先判斷該字節(jié)是否大于127,如果大于則將該字節(jié)個(gè)隨后的一個(gè)字節(jié)放過(guò),否則交給cjson去處理。

總結(jié)

以上是生活随笔為你收集整理的json mysql乱码问题_JSON数据乱码问题的全部?jī)?nèi)容,希望文章能夠幫你解決所遇到的問(wèn)題。

如果覺(jué)得生活随笔網(wǎng)站內(nèi)容還不錯(cuò),歡迎將生活随笔推薦給好友。