我想创建一个转换器,将 f 字符串的所有引号从单引号转换为三引号,但保持嵌套的 f 字符串完好无损。
例如,下一个表达式保持不变。
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}""")}
"""
我尝试了以下匹配器但没有成功:
class _FormattedStringEscapingTransformer(m.MatcherDecoratableTransformer):
@m.call_if_not_inside(
m.FormattedString(
parts=m.OneOf(
m.FormattedStringExpression(expression=m.TypeOf(m.FormattedString))
)
)
)
@m.leave(m.FormattedString())
def escape_f_string(
self, original_node: cst.FormattedString, updated_node: cst.FormattedString
) -> cst.FormattedString:
return updated_node.with_changes(start='f"""', end='"""')
class _FormattedStringEscapingTransformer(m.MatcherDecoratableTransformer):
@m.call_if_not_inside(
m.FormattedString(
parts=m.OneOf(
m.FormattedStringExpression(
expression=m.Not(m.FormattedString(parts=m.DoNotCare()))
)
)
)
)
@m.leave(m.FormattedString())
def escape_f_string(
self, original_node: cst.FormattedString, updated_node: cst.FormattedString
) -> cst.FormattedString:
return updated_node.with_changes(start='f"""', end='"""')
他们都不起作用。
如果内部 f 字符串表达式排除转换,正确的匹配器是什么?
我不认为
call_if_[not_]inside
是执行此操作的正确工具 - 它将始终调用具有匹配条件的节点 或其父级 ,而不是 只是其父级 :
https://libcst.readthedocs.io/en/latest/matchers.html#libcst.matchers.call_if_not_inside
仅当 it 或其父级之一与提供的匹配器不匹配时,才会调用用此装饰器装饰的方法。
将 f 字符串的所有引号从单引号转换为 ...,但保留嵌套的 f 字符串完整 翻译为 始终转换外部 f 字符串,然后在访问子 f 字符串时,不要转换它们。仅当同一变压器中有其他转换时才需要匹配器可装饰变压器实现,但类似这样的东西应该可以工作:
import libcst as cst
import libcst.matchers as m
class _FormattedStringEscapingTransformer(m.MatcherDecoratableTransformer):
_escapee_fstring_node: cst.FormattedString | None = None
@m.visit(m.FormattedString())
def visit_f_string(self, node: cst.FormattedString) -> None:
if self._escapee_fstring_node is None:
self._escapee_fstring_node = node
@m.leave(m.FormattedString())
def escape_f_string(
self, original_node: cst.FormattedString, updated_node: cst.FormattedString
) -> cst.FormattedString:
if original_node is self._escapee_fstring_node:
self._escapee_fstring_node = None
return updated_node.with_changes(start='f"""', end='"""')
return updated_node
>>> mod = cst.parse_module(
... '''
... f"Hello {developer_name}, My name is {_get_machine(f"{self.prop_a}, {self.prop_b}")}"
... '''
... )
...
>>> print(mod.visit(_FormattedStringEscapingTransformer()).code)
f"""Hello {developer_name}, My name is {_get_machine(f"{self.prop_a}, {self.prop_b}")}"""