使用.format(或f-string)时,如何在字符串中转义花括号({})字符?

2483

无法工作的示例:

print(" \{ Hello \} {0} ".format(42))

期望得到的输出:

 {Hello} 42 

1
参见:https://dev59.com/KVsV5IYBdhLWcg3w-i0C - dreftymac
26
想避免使用双花括号 ({{ }}) 的人可以使用 string.Template。在那里,您可以替换形式为 $foo 的标识符(方便生成 LaTeX 代码)。 - 0 _
2
对于那些想要避免双重大括号的人,而且不介意在他们的Python项目中添加另一个依赖项的人,也可以使用Jinja2来解决这个问题,它允许用户定义自定义占位符分隔符语法。 - dreftymac
23个回答

9

如果需要在字符串中包含两个花括号,那么变量的每侧都需要有5个花括号。

>>> myvar = 'test'
>>> "{{{{{0}}}}}".format(myvar)
'{{test}}'

3
对于使用f-strings的人,请在两侧使用4个大括号而不是5个。 - TerryA
1
@TerryA 在format()和f-strings之间大括号的行为没有区别。代码 a = 1; print('{{{{{a}}}}}'.format(a=a))a = 1; print(f'{{{{{a}}}}}') 会产生相同的结果。 - Kerrick Staley

6
如果您需要经常这样做,最好定义一个实用函数,让您可以使用任意的花括号替代物。例如:
def custom_format(string, brackets, *args, **kwargs):
    if len(brackets) != 2:
        raise ValueError('Expected two brackets. Got {}.'.format(len(brackets)))
    padded = string.replace('{', '{{').replace('}', '}}')
    substituted = padded.replace(brackets[0], '{').replace(brackets[1], '}')
    formatted = substituted.format(*args, **kwargs)
    return formatted

>>> custom_format('{{[cmd]} process 1}', brackets='[]', cmd='firefox.exe')
'{{firefox.exe} process 1}'

请注意,这将适用于括号是长度为2的字符串或两个字符串的可迭代对象(用于多字符分隔符)。

考虑过这个方法。当然,那也可以,而且算法更简单。但是,想象一下,如果你有很多这样的文本,并且只想在这里和那里进行参数化。每次创建输入字符串时,您不想手动替换所有这些大括号。您只想在这里和那里“插入”您的参数化。在这种情况下,我认为从用户角度来看,这种方法既易于思考又易于实现。我受到Linux的'sed'命令的启发,该命令具有类似的功能,可以根据方便选择任意分隔符。 - tvt173
简而言之,我宁愿让实用函数变得稍微复杂一些,也不想每次使用时都感到痛苦。如果我误解了你的建议,请告诉我。 - tvt173
我已经在我的public.lab空间https://github.com/dreftymac/public.lab/blob/master/topic/python/string.format/readme.md中添加了一个简短的演示。 - dreftymac

5

最近我遇到了这个问题,因为我想把字符串注入到预格式化的JSON中。 我的解决方案是创建一个帮助方法,像这样:

def preformat(msg):
    """ allow {{key}} to be used for formatting in text
    that already uses curly braces.  First switch this into
    something else, replace curlies with double curlies, and then
    switch back to regular braces
    """
    msg = msg.replace('{{', '<<<').replace('}}', '>>>')
    msg = msg.replace('{', '{{').replace('}', '}}')
    msg = msg.replace('<<<', '{').replace('>>>', '}')
    return msg

您可以执行以下操作:

您可以执行以下操作:

formatted = preformat("""
    {
        "foo": "{{bar}}"
    }""").format(bar="gas")

如果性能不是问题,那么它可以完成工作。


简单而优雅,易于集成到现有代码中,只需要进行少量修改。谢谢! - Column01
当然,假设您的文本一开始就没有包含任何<<<>>>,否则这些将被覆盖。最好使用转义策略以确保可靠性! - axolotl
你建议采用什么转义策略?无论如何,你都知道你的模板文本,并且可以在担心冲突的情况下修改魔术字符串。 - Kristján Valur
这种方法非常灵活,甚至可以借用Perl的约定来更加实用。只需1)选择一系列您知道不会出现在目标文本中的字符(例如QQX);2)将该序列用作变量占位符QQX<name>;3)进行正则表达式替换以将占位符转换为预期格式(例如)r'QQ<([^>]+)>','{$1}'另请参阅: perl quotelike operator - dreftymac

3

原因是,{}.format() 语法的一部分,所以在你的情况下,.format() 不识别 {Hello} ,因此抛出错误。

您可以通过使用双大括号{{}}来覆盖它,

x = " {{ Hello }} {0} "

或者

尝试使用%s进行文本格式化。

x = " { Hello } %s"
print x%(42)  

这很简单。我总是忘记百分号格式化。它在所有Python版本中仍然有效,并且使我的需要数字格式化的JSON字符串的快速测试更加清晰。 - Matthew

3

我来晚了。我尝试将括号放在替换元素中,像这样:

print('{0} {1}'.format('{hello}', '{world}'))

打印输出

{hello} {world}

严格来说,这并不是 OP 所要求的,因为他/她想要在格式字符串中保留括号,但这可能会对某些人有所帮助。


1
即使 print("{} {}".format("{hello}", "{world}")) 也可以工作。 - ankit

0

我使用双重{{ }}来防止fstring值注入,

例如,这是我的Postgres UPDATE语句,用于更新一个整数数组列,该列采用表达式{}来捕获数组,即:

ports = '{100,200,300}'

使用fstrings,则为:

ports = [1,2,3]

query = f"""
   UPDATE table SET ports = '{{{ports}}}' WHERE id = 1
"""

实际查询语句将是:

UPDATE table SET ports = '{1,2,3}'

这是一个有效的PostgreSQL语句


0
你可以使用“引用墙”来将格式化字符串部分与常规字符串部分分开。
来自:
print(f"{Hello} {42}")

print("{Hello}"f" {42}")

一个更清晰的例子是:
string = 10
print(f"{string} {word}")

输出:

NameError: name 'word' is not defined

现在,像这样添加引用墙:

string = 10
print(f"{string}"" {word}")

输出:

10 {word}

1
这看起来更像是连接,但思路不错。 - Delrius Euphoria
1
我建议不要这样做 - 它使用了一种语言特性,本身就是有争议的,并被Guido描述为一个错误(隐式字符串连接),并以一种不寻常且令人困惑的方式使用它。许多遇到这个问题的人将会很难弄清楚发生了什么。实际上,它只是简单明了地执行了f"{string}" + " {word}",但却以一种更加混乱的方式实现了这一点。 这让我想起了虚假的“获取集合中单个元素的运算符”=,如下所示: elem ,= {'single_element'} 它可以工作,但只会引起混乱! - Andrew McLeod

0

我在尝试打印可以复制粘贴到Latex文档中的文本时遇到了这个问题。我扩展了this answer并使用了命名替换字段:

假设您想打印出多个带有索引的变量的乘积,例如enter image description here,在Latex中将是$A_{ 0042 }*A_{ 3141 }*A_{ 2718 }*A_{ 0042 }$。下面的代码使用命名字段来完成任务,以便对于许多索引,它保持可读性:

idx_mapping = {'i1':42, 'i2':3141, 'i3':2178 }
print('$A_{{ {i1:04d} }} * A_{{ {i2:04d} }} * A_{{ {i3:04d} }} * A_{{ {i1:04d} }}$'.format(**idx_mapping))

0
如果您想打印花括号的一侧:
a=3
print(f'{"{"}{a}')
>>> {3

不必要的,如顶部答案所述,将 { 加倍仍然足够。因此,可以写成 f'{{{a}' - user202729

-1

如果你想要打印一个花括号(例如{),你可以使用{{,并且如果需要的话,你可以在字符串中添加更多的花括号。例如:

>>> f'{{ there is a curly brace on the left. Oh, and 1 + 1 is {1 + 1}'
'{ there is a curly brace on the left. Oh, and 1 + 1 is 2'

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接