作者:越大大雨天
链接:https://www.jianshu.com/p/27df6c3ae662
来源:简书

在大批量使用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,但也希望可以为遇到相似问题的你提供一个解决思路。该方式主要用到有正则异常捕获、正则提取异常中有用信息、递归修改文本参数内容,直至不再触发异常,返回最终所需结果。



作者:越大大雨天
链接:https://www.jianshu.com/p/27df6c3ae662
来源:简书
著作权归作者所有。商业转载请联系作者获得授权,非商业转载请注明出处。

Logo

为开发者提供学习成长、分享交流、生态实践、资源工具等服务,帮助开发者快速成长。

更多推荐