如何使用LibCST实现将单引号f-string转为三引号且正确处理嵌套场景的转换器
如何使用LibCST实现将单引号f-string转为三引号且正确处理嵌套场景的转换器
我来帮你搞定这个LibCST转换器的问题!你想要的效果是把外层的单/双引号f-string替换成对应的三引号,同时让内部嵌套的f-string保持原样对吧?之前你尝试的call_if_not_inside匹配逻辑可能没精准命中嵌套场景,咱们来调整一下实现思路。
核心思路
关键要准确区分外层非嵌套的f-string和内层嵌套的f-string:
- 外层f-string:没有被包含在另一个f-string的表达式部分里,需要把单/双引号改成三引号
- 内层嵌套f-string:作为其他f-string中
{}里的表达式内容,要保持原引号不变
完整实现代码
import libcst as cst import libcst.matchers as m class FormattedStringQuoteTransformer(cst.MatcherDecoratableTransformer): @m.call_if_not_inside( # 匹配"当前节点处于另一个f-string的表达式内容中"的场景,这类节点不处理 m.FormattedString( parts=m.Contains( m.FormattedStringExpression( expression=m.MatchIfTrue(lambda node: isinstance(node, cst.FormattedString)) ) ) ) ) @m.leave(m.FormattedString(quote=m.MatchIfTrue(lambda q: q in ("'", '"')))) def convert_single_quote_to_triple(self, original_node: cst.FormattedString, updated_node: cst.FormattedString) -> cst.FormattedString: # 根据原引号类型替换为对应的三引号 new_quote = "'''" if original_node.quote == "'" else '"""' return updated_node.with_changes(quote=new_quote)
代码解释
嵌套场景排除逻辑:
call_if_not_inside里的匹配器会检查当前f-string是否被包含在另一个f-string的parts中,且这个parts里存在一个FormattedStringExpression(也就是{}里的内容),而该表达式本身又是一个FormattedString——这样就精准定位了嵌套的f-string,这类节点会被跳过处理。引号转换逻辑:
leave装饰器专门匹配使用单引号或双引号的f-string,处理函数里会根据原引号的类型,替换成对应的三引号(单引号转''',双引号转""")。
测试效果
拿你给出的例子来测试:
原代码:
f"\ Hello {developer_name} My name is {_get_machine(f'{self.prop_a}, {self.prop_b}')} "
经过转换器处理后,会得到:
f"""\ Hello {developer_name} My name is {_get_machine(f'{self.prop_a}, {self.prop_b}')} """
完美实现了外层转三引号、内层嵌套f-string保持原样的需求~
额外注意点
- 这个逻辑支持多层嵌套的f-string,只有最外层的非嵌套f-string会被转换
- 如果原f-string已经是三引号,不会被修改,避免重复转换
备注:内容来源于stack exchange,提问作者Maxim Kirilov
相关产品推荐
相关产品推荐

