【问题标题】:How to read from a JSON file with unescaped backslashes?如何从带有非转义反斜杠的 JSON 文件中读取?
【发布时间】:2017-07-01 14:50:43
【问题描述】:

我有一个包含连接字符串的 JSON 文件:

abc.json

{
  "host":"1.2.3.4",
  "user":"abc",
  "passwd":"s&]\yz$&u42/",
  "dbname":"sample",
  "port":2341
}

这是我尝试读取数据的 Python 脚本:

 import psycopg2 as pg
 dbconn = "C:\abc.json"
 with open(dbconn) as conn_file:
     conn = json.load(conn_file)

它给了我这个错误:

json.decoder.JSONDecodeError: Invalid \escape: line 4 column 16 (char 53)

我该如何解决这个错误?

【问题讨论】:

  • 顺便说一句......如果这是一个真正的密码,你会想马上改变它。
  • 密码错误,没关系!

标签: python json python-2.7 escaping


【解决方案1】:

Python >= 2.7.15 似乎产生与 Python3 相同的错误消息:

test = """
{
  "host":"1.2.3.4",
  "user":"abc",
  "passwd":"s&]\yz$&u42/",
  "dbname":"sample",
  "port":2341
}
"""

print json.loads(test)

错误:

ValueError: Invalid \escape: line 5 column 16 (char 54)

稍微修改@Zero Piraeus's代码使其在Python2.7下工作:

import json
import re

def permissive_json_loads(text):
    _rePattern = re.compile(r'''(\d+)\)$''', re.MULTILINE)

    i = 0
    #  Make sure the loop is going to terminate.
    #  There wont be more iterations than the double amout of characters
    while True:
        i += 1
        if i > len(text) * 2:
            return
        try:
            data = json.loads(text)
        except ValueError, exc:
            exMsg = str(exc)
            if exMsg.startswith('Invalid \\escape'):
                m = re.search(_rePattern, exMsg)
                if not m:
                    return

                pos = int(m.groups()[0])
                print "Replacing at: %d" % pos
                text = text[:pos] + '\\' + text[pos:]
            else:
                raise
        else:
            return data

text = """
{
  "host":"1.2.3.4",
  "user":"abc",
  "passwd":"s&]\yz$&u42/",
  "dbname":"sample",
  "port":2341
}
"""

i = permissive_json_loads(text)
print i

打印:

Replacing at position: 54
{u'passwd': u's&]\\yz$&u42/', u'host': u'1.2.3.4', u'port': 2341, u'user': u'abc', u'dbname': u'sample'}

【讨论】:

    【解决方案2】:

    您的文件无效:在 JSON 中没有 \y 这样的转义序列,因此必须对裸反斜杠本身进行转义:\\

    如果可以的话,最简单的解决方案是通过转义反斜杠来修复您的文件,使其成为有效的 JSON。

    如果由于某种原因你不能,可以为json.loads() 编写一个包装器来捕获这个特定的错误并修补源文本:

    import json
    from json.decoder import JSONDecodeError
    
    def permissive_json_loads(text):
        while True:
            try:
                data = json.loads(text)
            except JSONDecodeError as exc:
                if exc.msg == 'Invalid \\escape':
                    text = text[:exc.pos] + '\\' + text[exc.pos:]
                else:
                    raise
            else:
                return data
    

    为了简单起见,上面的函数接受一个字符串而不是一个文件。

    这也是一种“大锤破解”的方法,反复尝试加载整个 JSON 文档并在找到它们时修复任何未转义的反斜杠——这对于很少出现问题的小型 JSON 文档是合理的,但较少如果您正在处理包含大量此类未转义反斜杠错误的大型 JSON 文档,则适用。

    它在行动:

    >>> print(text)
    {
      "host":"1.2.3.4",
      "user":"abc",
      "passwd":"s&]\yz$&u42/",
      "dbname":"sample",
      "port":2341
    }
    
    >>> config = permissive_json_loads(text)
    >>> print(config['passwd'])
    s&]\yz$&u42/
    

    在你的情况下,你会从你的文件中读入一个字符串,然后调用函数:

     dbconn = "C:\abc.json"
     with open(dbconn) as conn_file:
         conn_doc = conn_file.read()
     conn = permissive_json_loads(conn_doc)
    

    【讨论】:

    • 谢谢!我尝试将内容存储在文本文件中并运行导致错误:son.decoder.JSONDecodeError:预期值:第 1 行第 1 列(字符 0),请您建议我是否从文件中读取它会是有问题吗?
    • 您是否将文件名传递给函数?上面的函数将包含 JSON 的字符串作为参数,而不是文件名。您需要先打开文件并将其读入字符串。
    • 可以重写函数以获取文件或文件名,但在这种情况下,您要尝试修补格式错误的数据,最好保持简单尽可能。
    • 是的,我提到了一个文件名。想法是将此配置文件保存在单独的位置,因此需要从中读取文件。请问您能帮忙实现吗?
    • 如何将文件读入字符串是一个单独的(老实说非常基本)问题,但我已经编辑了答案以说明如何。
    猜你喜欢
    • 2019-02-13
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2014-09-20
    • 1970-01-01
    • 2020-08-24
    • 2019-02-02
    • 2023-04-08
    相关资源
    最近更新 更多