最新国产好看的视频,伊人天堂AV在线,国产Aaaaaa视频,蜜臀视频在线观看一区,人妻av色图,密臀久久久精品影片,青青视频免费观看毛片,久草在线观看视,国产三级精品色情在线

詳解Python在使用JSON時需要注意的編碼問題

 更新時間:2019年12月06日 11:31:11   作者:Abyssknight  
這篇文章主要介紹了詳解Python在使用JSON時需要注意的編碼問題,文中通過示例代碼介紹的非常詳細(xì),對大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價值,需要的朋友們下面隨著小編來一起學(xué)習(xí)學(xué)習(xí)吧

寫這篇文章的緣由是我使用 reqeusts 庫請求接口的時候, 直接使用請求參數(shù)里的 json 字段發(fā)送數(shù)據(jù), 但是服務(wù)器無法識別我發(fā)送的數(shù)據(jù), 排查了好久才知道 requests 內(nèi)部是使用 json.dumps 將字符串轉(zhuǎn)成 json 的, 而 json.dumps 默認(rèn)情況下會將 非ASCII 字符轉(zhuǎn)義, 也就是我發(fā)送數(shù)據(jù)中的中文被轉(zhuǎn)義了, 所以服務(wù)器無法識別. 這篇文章雖然是 json.dumps 問題的總結(jié), 但也會涉及到 字符編碼 問題, 所以就簡單先說一下 字符編碼.

Python 中的字符編碼

在 Python3 中, 字符 在內(nèi)存中是使用 Unicode 存儲的, 常規(guī)的字符使用 兩個字節(jié) 表示, 一些很生僻的字符就需要 四個字節(jié). 默認(rèn)使用 Unicode 存儲是什么意思呢, 那就是例子來解釋一下, 在 Python Shell 中輸入以下字符串 '\u4e2d\u6587', 觀察其輸出:

In [51]: '\u4e2d\u6587'
Out[51]: '中文'

輸出的為 中文 兩個字. 其實 \u4e2d 和 \u6587 分別表示 中 和 文 的 Unicode 編碼(術(shù)語稱為 碼點)的 十六進(jìn)制 表示, 在 Python3 中以 \u 開頭的字符串被解析為 Unicode 字符, 然后通過其十六進(jìn)制 碼點 解析出具體的字符, 所以 中文 的內(nèi)存表示即為 \u4e2d\u6587.

獲取字符 Unicode 碼點

標(biāo)準(zhǔn)庫提供了 ord 函數(shù)輸出一個字符的 Unicode 碼點, 使用 chr 函數(shù)將 碼點 轉(zhuǎn)換成 字符, 下面是示例:

In [54]: ord('中')
Out[54]: 20013

In [56]: chr(20013)
Out[56]: '中'

輸出的 碼點 是使用 十進(jìn)制 表示的, 可以使用以下代碼將整數(shù)格式化成十六進(jìn)制字符串:

'{0:04x}'.format(20013)

使用 json.dumps

有了前面的鋪墊, 就可以來說說 json.dumps 了. 下面以一個例子展開:

In [121]: json.dumps('中文', ensure_ascii=True)
Out[121]: '"\\u4e2d\\u6587"'

In [122]: json.dumps('中文', ensure_ascii=False)
Out[122]: '"中文"'

可以看到, 在 ensure_ascii 為 True 的情況下, 中文 被編碼成了 Unicode 碼, 為 False 才能正常顯示, 但是這跟 ASCII 有什么關(guān)系呢? 來看一下官方文檔 對這個參數(shù)的解釋:

如果 ensure_ascii 是 true (即默認(rèn)值),輸出保證將所有輸入的非 ASCII 字符轉(zhuǎn)義。如果 ensure_ascii 是 false,這些字符會原樣輸出。

現(xiàn)在稍微明白了, 在 ensure_ascii 為 True 的情況下, 如果字符串中存在 非ASCII 字符就將其轉(zhuǎn)義, 根據(jù)結(jié)果可以知道這個字符被轉(zhuǎn)義為 Unicode 碼并格式化成了一個字符串, 注意 "\\u4e2d\\u6587" 與 "\u4e2d\\u6587" 是不同的, 前者是長度為 12 的字符串, 后者會被 Python 直接解析為 中文, 長度為 2. 這也就是我一開始出現(xiàn)的問題, 直接將轉(zhuǎn)義的字符串在網(wǎng)絡(luò)上傳輸可能會無法被識別. 比如 中文 被轉(zhuǎn)義成 \\u4e2d\\u6587, 而服務(wù)器如果不知道它是被轉(zhuǎn)義過的字符串, 那它就是一個長度為 12 的普通字符串, 肯定會識別出錯. 而將 ensure_ascii 設(shè)為 False 就不會進(jìn)行轉(zhuǎn)義, 使用原始字符.

識別轉(zhuǎn)義字符

如果服務(wù)器收到數(shù)據(jù)后發(fā)現(xiàn)是被轉(zhuǎn)化過的, 那怎么識別呢? 其實被轉(zhuǎn)義字符串與使用 unicode_escape 對字符串進(jìn)行編碼再使用 utf-8 進(jìn)行解碼的結(jié)果一致, 代碼如下:

In [129]: msg
Out[129]: '中文'

In [130]: msg.encode('unicode_escape').decode('utf-8')
Out[130]: '\\u4e2d\\u6587'

所以識別只要反過來使用 utf-8 編碼再使用 unicode_escape 解碼就可以了.

轉(zhuǎn)義是如何進(jìn)行的

現(xiàn)在來看一下 json 到底是怎么對字符進(jìn)行轉(zhuǎn)義的. 在 json.dumps 源碼中仔細(xì)調(diào)試的話會發(fā)現(xiàn), 它調(diào)用的是 JSONEncoder.encode 方法, 而 encode 中的代碼片段如下:

if self.ensure_ascii:
  return encode_basestring_ascii(o)
else:
  return encode_basestring(o)

它會根據(jù) ensure_ascii 的值選擇調(diào)用函數(shù). 而 encode_basestring_ascii 的值是 (c_encode_basestring_ascii or py_encode_basestring_ascii), 也就是默認(rèn)是用 C 實現(xiàn)的版本, 其次使用 Python 實現(xiàn)的版本, 既然有 Python 版本, 當(dāng)然要看一下是怎么實現(xiàn)的, py_encode_basestring_ascii 可以直接使用 from json.encoder import py_encode_basestring_ascii 導(dǎo)入, 直接在其內(nèi)部就可以調(diào)試. 下面是其源碼:

def py_encode_basestring_ascii(s):
  """Return an ASCII-only JSON representation of a Python string

  """
  def replace(match):
    s = match.group(0)
    try:
      return ESCAPE_DCT[s]
    except KeyError:
      n = ord(s)
      if n < 0x10000:
        return '\\u{0:04x}'.format(n)
        #return '\\u%04x' % (n,)
      else:
        # surrogate pair
        n -= 0x10000
        s1 = 0xd800 | ((n >> 10) & 0x3ff)
        s2 = 0xdc00 | (n & 0x3ff)
        return '\\u{0:04x}\\u{1:04x}'.format(s1, s2)
  return '"' + ESCAPE_ASCII.sub(replace, s) + '"'

從最后的 return 可以看到它實際上是 正則替換 最后在前后添加 雙引號. ESCAPE_ASCII 的定義如下:

ESCAPE_ASCII = re.compile(r'([\\"]|[^\ -~])')

其中 ([\\"] 用于匹配 \\ 和 ", 而 [^\ -~] 表示 \ -~ 取反(這里的反斜杠貌似是對空格進(jìn)行轉(zhuǎn)義, 我不是很理解, 不進(jìn)行轉(zhuǎn)義依舊可以匹配到), 在 ASCII 表里, 空格字符 對應(yīng)十進(jìn)制是 40, ~ 是 176, 這是所有的可打印字符, 取反就是所有編碼不在 40 ~ 176 的字符, 所以中文就會被匹配到, 下面為 ASCII表:

對于匹配到的字符, 會傳入回調(diào)函數(shù) replace 做轉(zhuǎn)義. replace 函數(shù)中的 ESCAPE_DCT 為:

ESCAPE_DCT = {
  '\\': '\\\\',
  '"': '\\"',
  '\b': '\\b',
  '\f': '\\f',
  '\n': '\\n',
  '\r': '\\r',
  '\t': '\\t',
}

會對常用字符進(jìn)行轉(zhuǎn)義, 如果失敗就獲取它的 Unicode 碼點, 然后判斷是否為小于 0x10000 即是否為 兩字節(jié) 字符(兩字節(jié)最大為0xFFFF) , 如果是就格式化為 Unicode 碼, 如果不是就使用 四字節(jié) 表示.

總結(jié)

記得使用 requests 發(fā)送 JSON 數(shù)據(jù)時將中文編碼.

以上就是本文的全部內(nèi)容,希望對大家的學(xué)習(xí)有所幫助,也希望大家多多支持腳本之家。

相關(guān)文章

  • Python實現(xiàn)刪除某列中含有空值的行的示例代碼

    Python實現(xiàn)刪除某列中含有空值的行的示例代碼

    這篇文章主要介紹了Python實現(xiàn)刪除某列中含有空值的行的示例代碼,文中通過示例代碼介紹的非常詳細(xì),對大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價值,需要的朋友們下面隨著小編來一起學(xué)習(xí)學(xué)習(xí)吧
    2020-07-07
  • Python利用OpenCV和skimage實現(xiàn)圖像邊緣檢測

    Python利用OpenCV和skimage實現(xiàn)圖像邊緣檢測

    提取圖片的邊緣信息是底層數(shù)字圖像處理的基本任務(wù)之一。本文將通過OpenCV和skimage的?Canny?算法實現(xiàn)圖像邊緣檢測,感興趣的可以了解一下
    2022-12-12
  • Python中搜索和替換文件中的文本的實現(xiàn)(四種)

    Python中搜索和替換文件中的文本的實現(xiàn)(四種)

    本文主要介紹了Python中搜索和替換文件中的文本的實現(xiàn),文中通過示例代碼介紹的非常詳細(xì),具有一定的參考價值,感興趣的小伙伴們可以參考一下
    2021-10-10
  • Django 導(dǎo)出 Excel 代碼的實例詳解

    Django 導(dǎo)出 Excel 代碼的實例詳解

    本篇文章主要介紹了Django 導(dǎo)出 Excel 代碼的實例詳解,小編覺得挺不錯的,現(xiàn)在分享給大家,也給大家做個參考。一起跟隨小編過來看看吧
    2017-08-08
  • python opencv通過4坐標(biāo)剪裁圖片

    python opencv通過4坐標(biāo)剪裁圖片

    圖片剪裁是常用的方法,那么如何通過4坐標(biāo)剪裁圖片,本文就詳細(xì)的來介紹一下,感興趣的小伙伴們可以參考一下
    2021-06-06
  • python圖像處理基本操作總結(jié)(PIL庫、Matplotlib及Numpy)

    python圖像處理基本操作總結(jié)(PIL庫、Matplotlib及Numpy)

    這篇文章主要給大家介紹了關(guān)于python圖像處理基本操作的相關(guān)資料,主要利用的是PIL庫、Matplotlib及Numpy等處理方法,需要的朋友可以參考下
    2021-06-06
  • django將數(shù)組傳遞給前臺模板的方法

    django將數(shù)組傳遞給前臺模板的方法

    今天小編就為大家分享一篇django將數(shù)組傳遞給前臺模板的方法,具有很好的參考價值,希望對大家有所幫助。一起跟隨小編過來看看吧
    2019-08-08
  • python?序列去重并保持原始順序操作

    python?序列去重并保持原始順序操作

    這篇文章主要介紹了python序列去重并保持原始順序操作,文章圍繞了python?序列去重的相關(guān)資料展開詳細(xì)介紹,需要的小伙伴可以參考一下,希望對你的有所幫助
    2022-03-03
  • PyQt5實現(xiàn)界面(頁面)跳轉(zhuǎn)的示例代碼

    PyQt5實現(xiàn)界面(頁面)跳轉(zhuǎn)的示例代碼

    這篇文章主要介紹了PyQt5實現(xiàn)界面跳轉(zhuǎn)的示例代碼,文中通過示例代碼介紹的非常詳細(xì),對大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價值,需要的朋友們下面隨著小編來一起學(xué)習(xí)學(xué)習(xí)吧
    2021-04-04
  • keras 多任務(wù)多l(xiāng)oss實例

    keras 多任務(wù)多l(xiāng)oss實例

    這篇文章主要介紹了keras 多任務(wù)多l(xiāng)oss實例,具有很好的參考價值,希望對大家有所幫助。一起跟隨小編過來看看吧
    2020-06-06

最新評論

汕头市| 安乡县| 敦化市| 五台县| 德江县| 榆树市| 织金县| 九龙县| 前郭尔| 宁陵县| 山东省| 屯留县| 清涧县| 辛集市| 临颍县| 合江县| 伊宁县| 崇文区| 通榆县| 石林| 长汀县| 邯郸市| 铁力市| 阳新县| 进贤县| 乐安县| 南平市| 闽清县| 出国| 田东县| 赣州市| 澜沧| 耒阳市| 宁远县| 土默特右旗| 建昌县| 天峻县| 仁化县| 乌苏市| 开封县| 若羌县|