SWE · Coding

TikTok 模板替换:重复 {name}、未知参数与替换值里的占位符

单次匹配原模板,明确占位符语法与未知键处理,避免替换值再次被解释及正则replacement转义问题。

题目重点:单次匹配原模板,明确占位符语法与未知键处理,避免替换值再次被解释及正则replacement转义问题。

题意与假设

这道练习题保留了面经中值得训练的核心约束,并将需要澄清的条件单独列出。现场拿到变体时,先和面试官确认这些条件。

  • 训练占位符语法为{ASCII_identifier},identifier以字母/下划线开头,后续字母、数字或下划线。
  • 只对原模板做一轮替换;未知键保留原token,替换值必须是字符串,空字符串合法。
  • 多余右花括号作为普通文本保留,不擅自修正模板;不支持嵌套语法/转义花括号,这些需另定合同。

解题路线

  1. “替换内容重复”有两种含义:同一token出现多次,或替换值也含token。先规定一轮替换,再把所有原文本匹配交给回调处理,防止递归求值的循环。
  2. 使用匹配回调返回params[key],而不是把它作为正则replacement格式串。这样反斜杠、美元符号或组引用形式仍是字面值,不意外触发另一层替换语法。
  3. 不能按参数键循环调用replace;key顺序会影响替换值中的占位符。例如name={x}、x=Jack,循环替换可能输出Jack,而单轮应输出{x}。
  4. 未知键保留token使信息损失最小,但不是唯一合理政策:正式接口可要求报错或空串。区别必须在输入输出合同体现,不能靠默认字典访问抛KeyError决定产品行为。
  5. 题目中的多余右括号保留,所以输出为Hello, my name is Jack.}。若要求模板严格校验,应先完整parse再替换;部分替换后才发现错误容易留下不可回滚的半成品。
  6. 替换只是字符串生成,放进HTML、SQL或命令行时仍需对应语境的编码/参数化。比如HTML文本应作为文本节点插入,不能因为占位符来源于字典就宣称内容已安全。

手动走一遍

text={name} meets {name}; {missing},params.name={x}、params.x=Jack,一轮结果{x} meets {x}; {missing}。name为空串时两个匹配都变空;{bad-key}不属于声明的identifier语法,因此保持原文。

Python 参考实现

下面的代码按上文假设实现,适合本地运行并追加自己的测试用例。

代码区可横向滚动;使用键盘时,先聚焦代码区再按方向键查看。

"""Single-pass {ASCII_identifier} replacement; unknown keys stay unchanged.
Replacement values are strings, never recursively interpreted as templates.
"""
import re

_PATTERN = re.compile(r"\{([A-Za-z_][A-Za-z0-9_]*)\}")


def replace_placeholders(text, params):
    def replace(match):
        key = match.group(1)
        if key not in params:
            return match.group(0)
        value = params[key]
        if not isinstance(value, str):
            raise ValueError("replacement must be a string")
        return value
    return _PATTERN.sub(replace, text)

复杂度

此固定正则只匹配线性扫描的标识符结构;时间 O(模板长度+输出长度),空间 O(输出长度)。替换值很大时输出可能远大于模板,不能仅按输入长度估计资源。

易错点与追问

容易失分的边界

  • 只替换第一个匹配。
  • 参数循环导致依赖key顺序。
  • 替换值被当组引用或再次递归解析。
  • 静默删除未知键/多余括号。

继续深挖

  • 如果要求递归替换怎样检测参数依赖环?
  • 需要{{转义或嵌套语法如何设计parser?
  • 输出长度上限怎样执行?
  • JS实现如何保持回调和自有属性查询语义?
✓已复制微信号!