Python: 更新有占位符的字典字符串?

Python: update dict string that has placeholders?

考虑这个字符串:"{'a': A, 'b': B, 'c': 10}"。现在我想更新这个“字符串”并添加新键 d 假设值为 20,所以结果将是 "{'a': A, 'b': B, 'c': 10, 'd': 20}"

通常,您可以将字符串(evalliteral_eval)评估为字典,更新您想要的方式并将其转换回字符串。但是在这种情况下,有占位符,在评估时不会被识别。

更新它的最佳方法是什么,以便旧值保持不变,但“dict-string”已正确更新?

我认为你可以:

选项 1 - 添加

在字符串末尾“}”之前插入新字符串“, key: value”。

选项 2 - adding/updating

的 RagEx

1 - 使用 find() 并搜索密钥。如果存在,使用正则表达式替换:

re.replace(regex_search,regex_replace,contents)

所以使用类似的东西:

string = re.sub(r'key: (.+),', 'key: value', article)

2 - 如果 find() 失败,使用选项 1

的添加

如果只是在字符串末尾添加...

this_string = "{'a': A, 'b': B, 'c': 10}"
this_add = "'d': 20"
this_string = f"{this_string[:-1]}, {this_add}{this_string[-1]}"
print(this_string)

会输出

{'a': A, 'b': B, 'c': 10, 'd': 20}

如果您需要在中间插入新字符串,您可以使用 string.find 来定位索引并使用该索引号来做类似的事情。

它基本上是重写整个字符串,但是字符串是不可变的我们能做什么。

这绝不是最佳解决方案,但这是一种方法:

import re

dict_str = "{'a': A, 'b': B, 'c': 10}"

def update_dict(dict_str, **keyvals):
    """creates an updated dict_str

        Parameters:
            dict_str (str): current dict_str
            **keyvals: variable amounts of key-values

        Returns:
            str:updated string

    """
    new_entries = ", ".join(map(lambda keyval: f"'{keyval[0]}': {keyval[1]}", keyvals.items())) # create a string representation for each key-value and join by ','
    return dict_str.replace("}", f", {new_entries}{'}'}")   # update the dict_str by removing the last '}' and add the new entries

输出:

updated = update_dict(dict_str,
    d = 20,
    e = 30
)
print(updated)
{'a': A, 'b': B, 'c': 10, 'd': 20, 'e': 30}
some_dict = {
    'g': 2,
    'h': 3
}

updated = update_dict(dict_str,
    **some_dict
)
print(updated)
{'a': A, 'b': B, 'c': 10, 'g': 2, 'h': 3}

为了获得正确解析 dict 的更强大的解决方案,您可以子类化 lib2to3.refactor.RefactoringTool 以使用作为 lib2to3.fixer_base.BaseFix 子类的修复器重构代码,其模式寻找 dictsetmaker 节点,以及一个 transform 方法,该方法扩展了 children 列表的叶节点,叶节点包含将在字典中构成新的 key-value 对的标记:

from lib2to3 import fixer_base, refactor, pytree
from lib2to3.pgen2 import token

class AddKeyValue(fixer_base.BaseFix):
    PATTERN = "dictsetmaker"

    def transform(self, node, results):
        node.children.extend((
            pytree.Leaf(token.COMMA, ','),
            pytree.Leaf(token.STRING, "'d'", prefix=' '),
            pytree.Leaf(token.COLON, ':'),
            pytree.Leaf(token.NUMBER, 20, prefix=' ')
        ))
        return node

class Refactor(refactor.RefactoringTool):
    def __init__(self, fixers):
        self._fixers= [cls(None, None) for cls in fixers]
        super().__init__(None)

    def get_fixers(self):
        return self._fixers, []

s = "{'a': A, 'b': B, 'c': 10}"
print(Refactor([AddKeyValue]).refactor_string(s + '\n', ''))

这输出:

{'a': A, 'b': B, 'c': 10, 'd': 20}

lib2to3 是 round-trip 稳定的,因此在转换后保留所有空格,如果要在它之前插入空格,则应使用 prefix 指定新节点。

您可以在 lib2to3 模块的 Grammar.txt 中找到 Python 语法的定义。

演示:https://repl.it/@blhsing/RudeLimegreenConcentrate