【问题标题】:Python replace values in unknown structure JSON filePython替换未知结构JSON文件中的值
【发布时间】:2018-05-31 19:21:47
【问题描述】:

假设我有一个 JSON 文件,其结构未知或可能会随着时间的推移而改变 - 我想用我在 Python 中选择的字符串替换“REPLACE_ME”的所有值。

我发现的一切都假设我知道结构。例如,我可以使用json.load 读取 JSON,然后遍历字典进行替换,然后将其写回。这假设我知道键名、结构等。

如何将 JSON 文件中的所有给定字符串值替换为其他内容?

【问题讨论】:

标签: python json


【解决方案1】:

此函数递归地将所有等于值original 的字符串替换为值new

此函数适用于 python 结构 - 当然您可以在 json 文件上使用它 - 使用 json.load

它不会替换字典中的键 - 只是值。

def nested_replace( structure, original, new ):
    if type(structure) == list:
        return [nested_replace( item, original, new) for item in structure]

    if type(structure) == dict:
        return {key : nested_replace(value, original, new)
                     for key, value in structure.items() }

    if structure == original:
        return new
    else:
        return structure

d = [ 'replace', {'key1': 'replace', 'key2': ['replace', 'don\'t replace'] } ]
new_d = nested_replace(d, 'replace', 'now replaced')
print(new_d)
['now replaced', {'key1': 'now replaced', 'key2': ['now replaced', "don't replace"]}]

【讨论】:

    【解决方案2】:

    我认为,如果您想替换用引号括起来的任何键或值(因为引号在 json 中转义,除非它们是字符串分隔符的一部分),我认为没有太大风险。

    我会转储结构,执行str.replace(带双引号),然后再次解析:

    import json
    
    d = { 'foo': {'bar' : 'hello'}}
    
    d = json.loads(json.dumps(d).replace('"hello"','"hi"'))
    
    print(d)
    

    结果:

    {'foo': {'bar': 'hi'}}
    

    我不会冒险替换部分字符串或不带引号的字符串,因为它可能会更改文件的其他部分。我想不出用双引号替换字符串可以改变其他东西的例子。

    有一些“干净”的解决方案,比如改编自 Replace value in JSON file for key which can be nested by n levels,但值得付出努力吗?取决于你的要求。

    【讨论】:

      【解决方案3】:

      为什么不直接修改文件而不是将其视为 JSON?

      with open('filepath') as f:
          lines = f.readlines()
      for line in lines:
          line = line.replace('REPLACE_ME', 'whatever')
          with open('filepath_new', 'a') as f:
              f.write(line)
      

      【讨论】:

        【解决方案4】:

        可以将 JSON 文件加载到字典中并通过该字典进行递归以找到正确的值这是不必要的肌肉弯曲。

        最好的方法是简单地将文件视为字符串并以这种方式进行替换。

        json_file = 'my_file.json'
        with open(json_file) as f:
            file_data = f.read()
        
        file_data = file_data.replace('REPLACE_ME', 'new string')
        <...>
        
        with open(json_file, 'w') as f:
            f.write(file_data)
        
        json_data = json.loads(file_data)
        

        从这里可以重写文件,您可以继续使用json_data 作为字典。

        【讨论】:

          【解决方案5】:

          这取决于,如果你想将所有标题为“REPLACE_ME”的字符串放在同一个字符串中,你可以使用它。 for 循环遍历字典中的所有键,然后您可以使用键来选择字典中的每个值。如果它等于您的替换字符串,它将用您想要的字符串替换它。

          search_string = "REPLACE_ME"
          replacement = "SOME STRING"
          test = {"test1":"REPLACE_ME", "test2":"REPLACE_ME", "test3":"REPLACE_ME", "test4":"REPLACE_ME","test5":{"test6":"REPLACE_ME"}}
          
          
          def replace_nested(test):
          
              for key,value in test.items():
          
                  if type(value) is dict:
                      replace_nested(value)
                  else:
                      if value==search_string:
                          test[key] = replacement
          
          
          replace_nested(test)
          print(test)
          

          【讨论】:

          • 假设 JSON 没有嵌套,test 是字典,而不是 JSON 文件
          • 我添加了一个递归函数来包含嵌套的字典。你能把 JSON 转换成字典吗?
          • 它不需要是字典 - 甚至可以迭代列表。
          【解决方案6】:

          为了以动态的方式解决这个问题,我已经获得使用相同的 json 文件来声明我们要替换的变量。

          Json 文件:

          {
          "properties": {
          "property_1": "value1",
          "property_2": "value2"
          },
          "json_file_content": {
             "key_to_find": "{{property_1}} is my value"
             "dict1":{
                 "key_to_find": "{{property_2}} is my other value"
             }
          }
          

          Python代码(参考Replace value in JSON file for key which can be nested by n levels):

          import json    
          def fixup(self, a_dict:dict, k:str, subst_dict:dict) -> dict:
          """
          function inspired by another answers linked below
          """ 
              for key in a_dict.keys():
                  if key == k:
                      for s_k, s_v in subst_dict.items():
                          a_dict[key] = a_dict[key].replace("{{"+s_k+"}}",s_v)
                  elif type(a_dict[key]) is dict:
                      fixup(a_dict[key], k, subst_dict)
          # ...
          file_path = "my/file/path"
          if path.exists(file_path):
             with open(file_path, 'rt') as f:
             json_dict = json.load(f)
             fixup(json_dict ["json_file_content"],"key_to_find",json_dict ["properties"])
             print(json_dict) # json with variables resolved
          else:
             print("file not found")
          

          希望对你有帮助

          【讨论】:

            猜你喜欢
            • 2017-08-02
            • 2020-09-05
            • 1970-01-01
            • 2012-11-18
            • 1970-01-01
            • 1970-01-01
            • 2020-12-23
            • 2021-05-03
            • 1970-01-01
            相关资源
            最近更新 更多