【问题标题】:Dealing with mis-escaped characters in JSON处理 JSON 中的错误转义字符
【发布时间】:2016-10-07 22:45:48
【问题描述】:

我正在将一个 JSON 文件读入 Python,其中包含转义的单引号 (\')。这会导致各种打嗝,正如很好地讨论的那样,例如here。但是,我找不到任何关于如何解决该问题的信息。我刚刚做了一个

newstring=originalstring.replace(r"\'", "'")

事情解决了。但这似乎相当丑陋。我也找不到太多关于如何在 json docs 中处理这种事情(创建异常或其他东西)的材料。

  • 是否有针对此类问题的良好、干净的程序?

很遗憾,不可能回到源头。

感谢您的帮助!

【问题讨论】:

  • \' 字符序列确实是无效的 JSON,因为 JSON 中没有这样的转义序列。你最初是如何产生这个输出的?
  • 嗨 Martijn,我根本没有制作它,只是使用给我的东西。显然它是使用“导出到 PHPMyAdmin 的 JSON 插件”创建的。
  • 在这种情况下,请考虑向该项目提交错误报告。
  • 当然,我只是认为这可能是用户设置的问题(我从未使用过 PHPMyAdmin)。对于 json 插件 来说,这似乎是一件简单的事情?我会调查的。

标签: python json string file-io data-structures


【解决方案1】:

JSON standard 定义了一组特定的valid 2-character escape sequences\\\/\"\b\r\n\f 和一个\t, - 用于定义任何 Unicode 代码点的字符转义序列,\uhhhh\u 加上 4 个十六进制数字)。任何其他反斜杠序列加上其他字符都是无效的 JSON

如果你有一个 JSON 源,否则你无法修复,唯一的出路是删除无效序列,就像你对 str.replace() 所做的那样,即使它有点脆弱(它会 break 当引号前面有一个偶数反斜杠序列时)。

您也可以使用正则表达式,在其中删除 任何 未在有效序列中使用的反斜杠:

fixed = re.sub(r'(?<!\\)\\(?!["\\/bfnrt]|u[0-9a-fA-F]{4})', r'', inputstring)

这不会捕获像\\\ 这样的奇数反斜杠序列,但会捕获其他任何内容:

>>> import re, json
>>> broken = r'"JSON string with escaped quote: \' and various other broken escapes: \a \& \$ and a newline!\n"'
>>> json.loads(broken)
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
  File "/Users/mjpieters/Development/Library/buildout.python/parts/opt/lib/python3.5/json/__init__.py", line 319, in loads
    return _default_decoder.decode(s)
  File "/Users/mjpieters/Development/Library/buildout.python/parts/opt/lib/python3.5/json/decoder.py", line 339, in decode
    obj, end = self.raw_decode(s, idx=_w(s, 0).end())
  File "/Users/mjpieters/Development/Library/buildout.python/parts/opt/lib/python3.5/json/decoder.py", line 355, in raw_decode
    obj, end = self.scan_once(s, idx)
json.decoder.JSONDecodeError: Invalid \escape: line 1 column 34 (char 33)
>>> json.loads(re.sub(r'(?<!\\)\\(?!["\\/bfnrt]|u[0-9a-fA-F]{4})', r'', broken))
"JSON string with escaped quote: ' and various other broken escapes: a & $ and a newline!\n"

【讨论】:

    【解决方案2】:

    正确的做法是修复创建无效 JSON 文件的任何问题。但如果那不可能,我想更换是必要的。但是您应该使用正则表达式,这样它就不会用\' 替换\\' - 在这种情况下,第一个反斜杠正在转义第二个反斜杠,它们没有转义引号。消极的后视将防止这种情况发生。

    import re
    newstring = re.sub(r"(?<!\\)\\'", "'", originalstring)
    

    【讨论】:

      【解决方案3】:

      解决方案还不错。它看起来很丑,因为问题很丑 - 你有损坏的数据。它当然简单、优雅且有效。只有当子字符串\\'(这是三个字符,我没有转义任何东西)出现在任何地方时,它才会失败,即使这样,也只有在连续斜杠的数量是偶数的情况下。所以你的选择是:

      1. 只做你当前的事情,但首先检查if r"\\'" in originalstring,如果是则抛出错误。简单、安全、可能没问题。
      2. (\\\\)+ 或其他内容使用带有否定回溯的正则表达式。
      3. 捕捉错误并使用错误的属性来决定要替换的字符串部分。

      看看这个sn-p:

      import json
      from json.decoder import JSONDecodeError
      
      s = r'"\'"'
      print(s)
      try:
          print(json.loads(s))
      except JSONDecodeError as e:
          print(vars(e))
      

      输出:

      "\'"
      {'msg': 'Invalid \\escape', 'colno': 2, 'doc': '"\\\'"', 'pos': 1, 'lineno': 1}
      

      【讨论】:

      • 只有在 Python 3 中,异常才具有这些属性;在 Python 2 中,您将得到一个 ValueError 异常,并且您无法解析文本消息以获取此信息。
      • 你可以使用json.JSONDecodeError,不需要从json.decoder导入。
      • 是的,Python 2 给了我一个ValueError: Invalid \escape:
      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 2013-03-17
      • 2017-03-16
      • 2015-08-06
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多