開發過程中訪問接口時經常用到jq來過濾json,用著覺得不是很爽,于是自己搞一個舒服的 ^_^
先說需求:
輸入:參數1:被過濾對象(json、dict、list), 參數2:過濾路徑
輸出:過濾結果(python對象),默認格式化輸出結果,key按字母順序排列
支持過濾方式:
dict key過濾 .key
dict key列表 .keys()
dict value列表 .values()
dict key,value對 .iterms()
list過濾 .3 或 .[3]
list負索引 .-2 或 .[-2]
list切片1 .2:6 或 .[2:6]
list切片2 .2: 或 .[2:]
list切片3 .:6 或 .[:6]
list step1 .1:6:2 或 .[1:6:2]
list step2 .1::2 或 .[1::2]
list step3 .::2 或 .[::2]
string過濾..與list相同
string切片..與list相同
string 切片 step..與list相同
廢話不多說,直接上核心代碼,兼容Py2和Py3
from __future__ import unicode_literalsimport json
import sixdef ppt(obj, path='.', with_print=True, normal_path_print=False):base_string = str if six.PY3 else basestringobj = json.loads(obj) if isinstance(obj, base_string) else objfind_str, find_map = '', ['["%s"]', '[%s]', '%s', '.%s']for im in path.split('.'):if not im:continueif isinstance(obj, (list, tuple, base_string)):if im.startswith('[') and im.endswith(']'):im = im[1:-1]if ':' in im:slice_default = [0, len(obj), 1]obj, quota = obj[slice(*[int(sli) if sli else slice_default[i] for i, sli inenumerate(im.split(':'))])], 1else:obj, quota = obj[int(im)], 1else:if im in obj:obj, quota = obj[im], 0elif im.endswith('()'):obj, quota = list(getattr(obj, im[:-2])()), 3else:if im.isdigit():obj, quota = obj[int(im)], 1else:raise KeyError(im)find_str += find_map[quota] % imif with_print:print(obj if isinstance(obj, base_string) elsejson.dumps(obj,indent=4,sort_keys=True,ensure_ascii=False))if normal_path_print:print('get it normally with: <obj>%s' % find_str)return obj
函數名:ppt,pretty print, 想不起更好的簡短的命名了 ?_?
參數說明:
- obj 輸入的對象
- path='.' 過濾字符串
- with_print=True 是否格式化打印輸出過濾結果
- normal_path_print=False 是否輸出過濾器反解后的正常查找方式
舉例:
> test = '{"a": [1, 3, 4, 9, 10, 0, 5, 3, 7], "c": [{"h": 1, "d": [{"e": ["f", "g"]}]}], "b": "1234567890", "d": null}'
> ppt(test)
{"a": [1, 3, 4, 9, 10, 0, 5, 3, 7], "b": "1234567890", "c": [{"d": [{"e": ["f", "g"]}], "h": 1}], "d": null
}
上述輸出key按字母順序排序
> ppt(test, '.a.::2', normal_path_print=True)
[1, 4, 10, 5, 7
]
get it normally with: <obj>["a"][::2]
> ppt(test, '.c.0.keys()', normal_path_print=True)
["h", "d"
]
get it normally with: <obj>["c"][0].keys()
方便的地方:
如 一個復雜的引用數據的方式
['all_angles'][0]['nodes'][-1]['children'][1]['children'][3]['id']
換用更簡單的方式,可以更簡單快速的定位數據:'all_angles.0.nodes.-1.children.1.children.3.id'