【问题标题】:Python how convert single quotes to double quotes to format as json stringPython如何将单引号转换为双引号以格式化为json字符串
【发布时间】:2018-05-19 11:28:16
【问题描述】:

我有一个文件,其中每一行都有这样的文字(代表电影的演员表):

[{'cast_id': 23, 'character': "Roger 'Verbal' Kint", 'credit_id': '52fe4260c3a36847f8019af7', 'gender': 2, 'id': 1979, 'name': 'Kevin Spacey', 'order': 5, 'profile_path': '/x7wF050iuCASefLLG75s2uDPFUu.jpg'}, {'cast_id': 27, 'character': 'Edie's Finneran', 'credit_id': '52fe4260c3a36847f8019b07', 'gender': 1, 'id': 2179, 'name': 'Suzy Amis', 'order': 6, 'profile_path': '/b1pjkncyLuBtMUmqD1MztD2SG80.jpg'}]

我需要将其转换为有效的 json 字符串,从而仅将必要的单引号转换为双引号(例如,单词 Verbal 周围的单引号不得转换,文本中的最终撇号也不应转换)。

我正在使用 python 3.x。我需要找到一个正则表达式,它只会将正确的单引号转换为双引号,因此整个文本会产生一个有效的 json 字符串。任何想法?

【问题讨论】:

  • 文件是由什么产生的?正确的做法是将其解析为字典列表,然后使用json.dump 对其进行编码。正则表达式就出来了;这不是常规语言。
  • import json;json.dumps(your_dict)
  • @AmitTripathi 这还不是dict;它是文件中的一个字符串。
  • 您的输入存在严重问题:值 Edie's Finneran 用单引号括起来;没有解析器能够分辨出撇号不是结束引号。您将不得不修复生成该文件的任何内容,在这种情况下,您不妨首先让它输出 JSON。
  • 你还没有回答这个问题:这个字符串是从哪里来的?为什么它还不是 json 兼容的?有多少?

标签: python json regex double-quotes single-quotes


【解决方案1】:

首先,您作为示例给出的行是不可解析的! … 'Edie's Finneran' … 包含语法错误,无论如何。

假设您可以控制输入,您可以简单地使用eval() 来读取文件。 (虽然,在那种情况下,人们会想知道为什么一开始就不能生成有效的 JSON……)

>>> f = open('list.txt', 'r')
>>> s = f.read().strip()
>>> l = eval(s)

>>> import pprint
>>> pprint.pprint(l)
[{'cast_id': 23,
  'character': "Roger 'Verbal' Kint",
  ...
  'profile_path': '/b1pjkncyLuBtMUmqD1MztD2SG80.jpg'}]

>>> import json
>>> json.dumps(l)
'[{"cast_id": 23, "character": "Roger \'Verbal\' Kint", "credit_id": "52fe4260ca36847f8019af7", "gender": 2, "id": 1979, "name": "Kevin Spacey", "order": 5, "rofile_path": "/x7wF050iuCASefLLG75s2uDPFUu.jpg"}, {"cast_id": 27, "character":"Edie\'s Finneran", "credit_id": "52fe4260c3a36847f8019b07", "gender": 1, "id":2179, "name": "Suzy Amis", "order": 6, "profile_path": "/b1pjkncyLuBtMUmqD1MztDSG80.jpg"}]'

如果您无法控制输入,这是非常危险的,因为它会使您面临代码注入攻击。

我怎么强调都不过分,最好的解决方案是首先生成有效的 JSON。

【讨论】:

    【解决方案2】:

    如果您无法控制 JSON 数据,请不要eval()它!

    我创建了一个简单的 JSON 校正机制,因为这样更安全:

    def correctSingleQuoteJSON(s):
        rstr = ""
        escaped = False
    
        for c in s:
        
            if c == "'" and not escaped:
                c = '"' # replace single with double quote
            
            elif c == "'" and escaped:
                rstr = rstr[:-1] # remove escape character before single quotes
            
            elif c == '"':
                c = '\\' + c # escape existing double quotes
       
            escaped = (c == "\\") # check for an escape character
            rstr += c # append the correct json
        
        return rstr
    

    您可以通过以下方式使用该功能:

    import json
    
    singleQuoteJson = "[{'cast_id': 23, 'character': 'Roger \\'Verbal\\' Kint', 'credit_id': '52fe4260c3a36847f8019af7', 'gender': 2, 'id': 1979, 'name': 'Kevin Spacey', 'order': 5, 'profile_path': '/x7wF050iuCASefLLG75s2uDPFUu.jpg'}, {'cast_id': 27, 'character': 'Edie\\'s Finneran', 'credit_id': '52fe4260c3a36847f8019b07', 'gender': 1, 'id': 2179, 'name': 'Suzy Amis', 'order': 6, 'profile_path': '/b1pjkncyLuBtMUmqD1MztD2SG80.jpg'}]"
    
    correctJson = correctSingleQuoteJSON(singleQuoteJson)
    print(json.loads(correctJson))
    

    【讨论】:

      【解决方案3】:

      这是获得所需输出的代码

      import ast
      def getJson(filepath):
          fr = open(filepath, 'r')
          lines = []
          for line in fr.readlines():
              line_split = line.split(",")
              set_line_split = []
              for i in line_split:
                  i_split = i.split(":")
                  i_set_split = []
                  for split_i in i_split:
                      set_split_i = ""
                      rev = ""
                      i = 0
                      for ch in split_i:
                          if ch in ['\"','\'']:
                              set_split_i += ch
                              i += 1
                              break
                          else:
                              set_split_i += ch
                              i += 1
                      i_rev = (split_i[i:])[::-1]
                      state = False
                      for ch in i_rev:
                          if ch in ['\"','\''] and state == False:
                              rev += ch
                              state = True
                          elif ch in ['\"','\''] and state == True:
                              rev += ch+"\\"
                          else:
                              rev += ch
                      i_rev = rev[::-1]
                      set_split_i += i_rev
                      i_set_split.append(set_split_i)
                  set_line_split.append(":".join(i_set_split))
              line_modified = ",".join(set_line_split)
              lines.append(ast.literal_eval(str(line_modified)))
          return lines
      lines = getJson('test.txt')
      for i in lines:
          print(i)
      

      【讨论】:

      • 大人。您可以改为使用 '"'.join(str.split("'"))"\"".join(str.split("'")) 以提高可读性
      【解决方案4】:

      除了 eval() (在 user3850 的回答中提到),您可以使用 ast.literal_eval

      这已经在线程中讨论过:Using python's eval() vs. ast.literal_eval()?

      您还可以查看以下来自 Kaggle 竞赛的讨论主题,其数据与 OP 提到的类似:

      https://www.kaggle.com/c/tmdb-box-office-prediction/discussion/89313#latest-517927 https://www.kaggle.com/c/tmdb-box-office-prediction/discussion/80045#latest-518338

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 2016-09-23
        • 1970-01-01
        • 1970-01-01
        • 2012-07-19
        • 1970-01-01
        • 2019-10-04
        • 1970-01-01
        • 1970-01-01
        相关资源
        最近更新 更多