Python 中的多行字符串格式化

问题描述 投票:0回答:4

首先,我正在努力获得如下所示的所需输出:

*********************************************************************
                                 hello
********************************************************************* 

为了实现这一目标,我已将所需的输出分配给具有多行字符串的变量,并使用格式打印相同的内容。

$ cat varibale.py 
decorator = """ **********************************************************************
                               {}
            ********************************************************************** """
print(decorator.format("hello"))

输出:

**********************************************************************
                               hello
            **********************************************************************

上述方法的问题是输出第三行中的额外空格,这看起来很奇怪。

我可以通过以下方式实现这一目标

$ cat varibale.py 
decorator = """ **********************************************************************
                             {}
********************************************************************* 
"""
print(decorator.format("hello"))

输出:

 **********************************************************************
                             hello
********************************************************************* 

但是这样我的代码看起来不太好,因为它没有遵循缩进。

请建议实现所需输出的正确方法。

python formatting multiline
4个回答
13
投票

使多行文字字符串看起来不错的一种方法是使用反斜杠来转义换行符,如下所示:

s = '''\
*********************************************************************
                                 hello
*********************************************************************
'''
print(s)

输出

*********************************************************************
                                 hello
*********************************************************************

但是,PEP-008 不鼓励这样使用反斜杠。它太脆弱了:如果反斜杠和换行符之间有空格,那么换行符将不会被转义,并且反斜杠将被打印。

一种更通用的方法是使用一个函数来计算居中文本所需的填充量,并通过嵌套格式说明符应用它。例如:

def banner(s, width=69):
    stars = '*' * width
    pad = (width + len(s)) // 2
    return '{0}\n{1:>{2}}\n{0}'.format(stars, s, pad)

print(banner('hello'))
print(banner('Hello, world', width=16))

输出

*********************************************************************
                                hello
*********************************************************************
****************
  Hello, world
****************

如何运作

该格式字符串有点密集,所以我想我应该尝试解释一下。 ;) 有关此主题的完整信息,请参阅文档中的格式字符串语法。下面的解释借用并解释了这些文档。

'{0}\n{1:>{2}}\n{0}'.format(stars, s, pad)

格式字符串中

{}
中包含的内容称为“替换字段”。替换字段中的第一项是可选字段名称。这让我们可以确定
.format
的哪个参数与此替换字段匹配。字段名称有几种可能的变体,此格式字符串使用数字名称,因此它通过位置来标识
.format
参数。即0对应
stars
,1对应
s
,2对应
pad

如果没有给出字段名称,它们会自动填充数字 0、1、2、... 等(除非您使用的是 Python 2.6,其中字段名称是强制性的)。这在大多数情况下都非常有用,因此大多数格式字符串都不需要使用字段名称。

在字段名称之后,我们可以给出一个“格式说明符”或“格式规范”,它描述了如何呈现值。冒号

:
将字段名称与格式规范分隔开。如果您不提供格式规范,那么您将获得默认格式规范,并且大多数情况下这就足够了。但在这里我们确实想要更多的控制,所以我们需要提供格式规范。

在表单规范中,

>
符号强制字段在可用空间内右对齐。在对齐标志之后我们可以提供一个数字来指定最小字段宽度;如果需要,该字段会自动变大。

例如,

'{0:>6}'.format('test')
表示将参数 0(“测试”)放在至少 6 个字符宽的空间中,并向右对齐。结果是字符串
'  test'
.

但是格式规范实际上可以包含一个全新的替换字段!这允许我们提供一个变量来控制字段宽度。因此,在我的格式字符串中,

{1:>{2}}
表示将arg 1放在这里(
s
),在宽度由arg 2(
pad
)给定的字段中右对齐。仅允许一层替换字段嵌套,但很难想象您实际上想要更深层次嵌套的情况。

所以把它们放在一起:

'{0}\n{1:>{2}}\n{0}'
告诉
.format
使用默认格式规范构建一个以 arg 0 (
stars
) 开头的字符串,后跟换行符,后跟 arg 1 (
s
) 右对齐在宽度为
pad
的字段中,后跟另一个换行符,最后再跟 arg 0 (
stars
)。

我希望这有足够的意义。 :)


在 Python 3.6+ 中,我们可以使用 f 字符串:

def banner(s, width=69):
    stars = '*' * width
    pad = (width + len(s)) // 2
    return f'{stars}\n{s:>{pad}}\n{stars}'

8
投票

您可以继续执行以下操作:

print('*'*80)
print('{msg:^80s}'.format(msg = 'HELLO')) #^ centers the message
print('*'*80)

或者如果你想要动态的文本宽度:

def fn(msg, w = 80):
    delim = '*'*w
    fmt = '{msg:^%ds}'%w

    print(delim)
    print(fmt.format(msg=msg))
    print(delim)

fn('hello')

或者如果您需要写入文件,则可以使用稍微通用的版本:

import sys

def fn(msg, w = 80, F = sys.stdout):
    delim = '*'*w
    fmt = '{delim:s}\n{msg:^%ds}\n{delim:s}\n'%w
    F.write(fmt.format(delim = delim, msg = msg))

fn('hello')

0
投票

也许:

print '*' * 80 + '\n' + ' ' * 38 + 'hello' + '\n' + '*' *80

或 如果是python3

a = lambda x,c,mess: print(c*x + ('\n' if not mess else mess))
a(80, '*', None)
a(38, ' ', 'Hello')
a(80, '*', None)

0
投票

从 Python 3.6 开始,可以在格式化字符串文字中完成格式化,也可以跨越多行。格式化参数(例如宽度)通常作为整数文字添加;要使用任意整数表达式,请将其括在花括号中。

在给定的情况下,这

print(f"""{'*'*width}
{'hello':^{width}}
{'*'*width}""")

可能看起来比

更令人困惑
print(f"{'*'*width}\n{'hello':^{width}}\n{'*'*width}")

但是当涉及到动态生成代码时,通过使用多行格式化字符串文字,您可以更轻松地实现正确的缩进和良好的可读性。

def gen_recursion(name, op, neutral): return f"""
def {name}(n):
    if n > {neutral}:
        return n {op} {name}(n-1)
    else:
        return {neutral}
"""

samples = (
    ('gauss', '+', 0),
    ('factorial', '*', 1)
)
for (name, op, neutral) in samples:
    s = gen_recursion(name, op, neutral)
    print(s)
    exec(s, globals())
    s = f"{name}(5)"
    print(f"{s} -> {eval(s)}")
© www.soinside.com 2019 - 2024. All rights reserved.