【问题标题】:How can I replace sub-strings of a large string based on a dictionary in Python?如何根据 Python 中的字典替换大字符串的子字符串?
【发布时间】:2011-10-12 10:22:08
【问题描述】:

我有一个长字符串(一个“模板”),其中包含 %MARK% 形式的“替换点”(单个给定标记的字符串中也可能出现更多次)。我想替换这些由 Python 字典控制的标记(它不包含标记的 % 符号),例如:

rep_dict = { "TITLE": "This is my title", "CONTENT": "Here it is the content" }

问题:简单的逐个调用replace()方法不是很好的解决方案:之前的替换可能包含这些标记之一,那么不能替换!

解决方案应该足够快,因为我有很大的模板,我需要在一个大循环中替换其中的许多。我有一个非常丑陋且冗长的实现,其中包含许多 find(),在替换过程中计算原始字符串中的偏移量等。我希望有一个更好、更紧凑和更快的解决方案。

【问题讨论】:

  • 很遗憾您使用 %MARK% 而不是 {MARK},因为您可以在字典中使用传统的字符串格式。也可以使用 ${MARK} 或 $MARK 使用字符串模板。
  • @joaquin 你的意思是%(MARK) 还是{MARK}%... 表示法已弃用,{...} 表示法要求他使用双纯文本花括号:{{these braces make it to the output string}}, {these do not}
  • 不,我指的不是% 的插值(顺便说一句,它还没有消失的日期,尽管说了些什么),而是string.Template。我重新编辑并完成了我的评论

标签: python string replace


【解决方案1】:

最简单的解决方案是

import re
re.sub(r'%(.+?)%', lambda m: rep_dict[m.group(1)], YOUR_TEMPLATE)

不够快?有人说'不要使用正则表达式',你服从了吗?使用 Python 中的一些代码解析模板会更加复杂和缓慢(不要忘记,re 是用 C 编写的)。

【讨论】:

  • 谢谢,好吧,我不想故意避免使用正则表达式(这更像是我在 Python 中有点初学者的情况)......但是,这是一个不错且“优雅”的解决方案它有一个小问题:模板可能包含一个标记,它不在rep_dict中。在这种情况下,此解决方案会产生异常。如果 rep_dict 中没有替换信息,我将需要返回字符串中未修改的 %...% 标记。
  • 如果你想忽略无效标记,你应该使用rep_dict.get(m.group(1), m.group())而不是rep_dict[m.group(1)]docs.python.org/library/stdtypes.html#dict.get
  • 到目前为止,这是我最好的解决方案(里面有更多的实现细节): def _replace_by_dict(rep, s): s = re.split("(%[A-Z0-9 ]{1,32}%)", s) for a, b in rep.items(): for c in range(len(s)): if s[c] == "%" + a + "%": s[c] = b return "".join(s) 它是在我提出这个问题并且在我阅读你的答案之前写的。但是您的解决方案要优雅得多,只是我已经提到过“未处理的标记”有问题。
  • 你可以抓住 KeyError 和 pass
  • 很好,您的评论帮助我现在理解了这一点。谢谢你的回答/cmets!
【解决方案2】:

这太棒了。一直以没时间学RegEx为借口, 但始终尊重它。这篇文章给了我开始的必要条件。这是我的解决方案 不过,我发现群呼在字典参数中混淆了:

retVal          = re.sub(r'%title', theTitle, template)
retVal          = re.sub(r'%([a-z]+?)+', \
                    lambda m: myDict.get(m.group(0)[1:], ''), retVal)

title 不在字典中,这就是我先做的原因。团队中其他人的要求。

【讨论】:

    最近更新 更多