在大批量使用json.loads()
语法时遇到了以下的错误,导致后续的大量内容无法正常加载。
# 错误1:
json.decoder.JSONDecodeError: Invalid \escape: line 1 column 10 (char 9)
# 错误2:
json.decoder.JSONDecodeError: Invalid control character at: line 1 column 7 (char 6)
这类错误都是:json.decoder.JSONDecodeError: Invalid XXX: line X column X (char X)相似的格式
情景复原
import json
data_str = '[{"text": "这是一个测试文本: \\abcd"}]'
完整错误如下:
Traceback (most recent call last):
File "/Library/Frameworks/Python.framework/Versions/3.7/lib/python3.7/site-packages/IPython/core/interactiveshell.py", line 3326, in run_code
exec(code_obj, self.user_global_ns, self.user_ns)
File "<ipython-input-19-ab5630329529>", line 1, in <module>
json.loads('{"a":"\\abcd"}')
File "/Library/Frameworks/Python.framework/Versions/3.7/lib/python3.7/json/__init__.py", line 348, in loads
return _default_decoder.decode(s)
File "/Library/Frameworks/Python.framework/Versions/3.7/lib/python3.7/json/decoder.py", line 337, in decode
obj, end = self.raw_decode(s, idx=_w(s, 0).end())
File "/Library/Frameworks/Python.framework/Versions/3.7/lib/python3.7/json/decoder.py", line 353, in raw_decode
obj, end = self.scan_once(s, idx)
json.decoder.JSONDecodeError: Invalid \escape: line 1 column 7 (char 6)
原因分析:
这种类似问题是由于字符串数据中存在一些特殊字符,且大概率是\
反斜杠,也可能是其他特殊无法识别的字符比如生僻中文等。
解决办法
网上很多解决办法是直接找到问题字符串,删除、转义或者修改后重新使用json.loads()
进行加载。
但该办法并不适合我的情况,由于我需要大规模批量的处理一些无法人眼筛选的数据,且每一条数据都不能丢弃。因此我的解决办法是触发异常后自动找到问题字符所在位置,并删除或替换掉引发异常的字符,再重新加载。
使用正则+递归自动替换非法字符串
我们可以注意上面的异常信息,内容char()
中包含了导致异常的字符串的索引位置,我们可以利用该信息对原始字符串进行修复。
这里用以下代码重现一下解决思路:
import json
import re
def loads_str(data_str):
try:
result = json.loads(data_str)
print("最终json加载结果:{}".format(result))
return result
except Exception as e:
print("异常信息e:{}".format(e))
error_index = re.findall(r"char (\d+)\)", str(e))
if error_index:
error_str = data_str[int(error_index[0])]
data_str = data_str.replace(error_str, "<?>")
print("替换异常字符串{} 后的文本内容{}".format(error_str, data_str))
# 该处将处理结果继续递归处理
return loads_str(data_str)
if __name__ == '__main__':
data_str = '[{"text": "这是一个测试文本: \a aaa\b aaaa \ caaaa \\ aa\\"}]'
result = loads_str(data_str=data_str)
print("------------------------------------")
print(result)
输出结果如下:
异常信息e:Invalid control character at: line 1 column 22 (char 21)
替换异常字符串� 后的文本内容[{"text": "这是一个测试文本: <?> aa aaaa \ caaaa \ aa\"}]
异常信息e:Invalid control character at: line 1 column 29 (char 28)
替换异常字符 后的文本内容[{"text": "这是一个测试文本: <?> aaa<?> aaaa \ caaaa \ aa\"}]
异常信息e:Invalid \escape: line 1 column 38 (char 37)
替换异常字符串\ 后的文本内容[{"text": "这是一个测试文本: <?> aaa<?> aaaa <?> caaaa <?> aa<?>"}]
最终json加载结果:[{'text': '这是一个测试文本: <?> aaa<?> aaaa <?> caaaa <?> aa<?>'}]
------------------------------------
[{'text': '这是一个测试文本: <?> aaa<?> aaaa <?> caaaa <?> aa<?>'}]
通过print()方法可观察到,使用该递归函数可以自动逐步替换掉导致异常的特殊字符。可以在批量处理时调用获取结果。
总结
当然这只是一个demo,但也希望可以为遇到相似问题的你提供一个解决思路。该方式主要用到有正则异常捕获、正则提取异常中有用信息、递归修改文本参数内容,直至不再触发异常,返回最终所需结果。
网友评论