python 中的多行字符串格式

multi line string formatting in python

首先,我正在努力获得这样的期望输出:

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

为了实现这一点,我已将 所需的输出分配给具有多行字符串 的变量,并使用 format.[=16 打印相同的内容=]

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

输出:

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

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

我可以通过以下方式实现这一点:

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

输出:

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

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

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

你可以继续,例如:

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')

也许:

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)

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

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

输出

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

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

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

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
****************

工作原理

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

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

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

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

在字段名称之后,我们可以给出一个“格式说明符”或“格式规范”来描述值的显示方式。冒号 : 将字段名称与格式规范分开。如果您不提供格式规范,那么您会得到一个默认格式,大多数情况下这就足够了。但在这里我们确实需要更多的控制,所以我们需要提供格式规范。

在表单规范中,> 符号强制字段在可用 space 内右对齐。在对齐符号之后,我们可以提供一个数字来指定最小字段宽度;如有必要,该字段将自动变大。

例如,'{0:>6}'.format('test') 表示将参数 0 ('test') 放入至少 6 个字符宽且右对齐的 space 中。结果是字符串 ' 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}'