【问题标题】:Preserving indentation in a triple-quoted fstring在三引号 fstring 中保留缩进
【发布时间】:2019-07-24 03:35:51
【问题描述】:

我正在尝试在 Python3(.7) 中使用三引号字符串来构建一些格式化字符串。

我有一个内部字符串列表,都需要在其中添加标签:

    This is some text
    across multiple
    lines.

还有一个应该包含内部字符串的字符串

data{
    // string goes here
}

创建内部字符串时,我无法对其进行制表符。所以,我的想法是使用dedent 和 Python3 三重引号 fstrings:

import textwrap

inner_str = textwrap.dedent(
    '''\
    This is some text
    across multiple
    lines.'''
)

full_str = textwrap.dedent(
    f'''\
    data{{
        // This should all be tabbed
        {inner_str}
    }}'''
)

print(full_str)

但是,缩进没有被维护:

    data{
        // This should all be tabbed
        This is some text
across multiple
lines.
    }

想要的结果:

data{
    // This should all be tabbed
    This is some text
    across multiple
    lines.
}

如何在不预先标记内部字符串的情况下保留 fstring 的缩进?

【问题讨论】:

  • 您是否尝试过使用\n\t 作为格式化选项?

标签: python python-3.x indentation f-string


【解决方案1】:

这似乎提供了你想要的。

import textwrap

inner_str = textwrap.dedent(
    '''\
    This is some text
    across multiple
    lines.'''
)

full_str = textwrap.dedent(
    f'''
    data{{
{textwrap.indent(inner_str, "        ")}
    }}'''
)

更好的解决方案:

idt = str.maketrans({'\n': "\n        "})
print(textwrap.dedent(
    f'''
    data{{
        {inner_str.translate(idt)}
    }}'''
))

另一种自定义标签宽度的解决方案:

def indent_inner(inner_str, indent):
    return inner_str.replace('\n', '\n' + indent)   # os.linesep could be used if the function is needed across different OSs

print(textwrap.dedent(
    f'''
    data{{
        {indent_inner(inner_str, "        ")}
    }}'''
))

【讨论】:

  • 这很好,只是内行代码在 f-string 期间不能制表符,这破坏了最初用 dedent 解决的可读性问题。
  • 我已经用另一个解决方案更新了答案。如果它满足您的需求,您可以考虑投票并接受答案。
【解决方案2】:

这里的答案似乎都不是我想要的,所以我正在用一个尽可能接近我所寻找的解决方案来回答我自己的问题。不需要预先对数据进行制表符来定义其缩进级别,也不需要不缩进行(这会破坏可读性)。而是在使用时传递 fstring 中当前行的缩进级别。

不完美,但可以。

import textwrap


def code_indent(text, tab_sz, tab_chr=' '):
    def indented_lines():
        for i, line in enumerate(text.splitlines(True)):
            yield (
                tab_chr * tab_sz + line if line.strip() else line
            ) if i else line
    return ''.join(indented_lines())


inner_str = textwrap.dedent(
    '''\
    This is some text
    across multiple
    lines.'''
)


full_str = textwrap.dedent(
    f'''
    data{{
        {code_indent(inner_str, 8)}
    }}'''
)

print(full_str)

【讨论】:

    【解决方案3】:

    编辑以避免标签inner_str

    import textwrap
    
    line_tab = '\n\t'
    
    inner_str = f'''\
    This is some text
    across multiple
    lines.
    '''
    
    full_str = textwrap.dedent(f'''\
    data{{
        // This should all be tabbed 
        {line_tab.join(inner_str.splitlines())}
    }}''')
                               )
    
    print(full_str)
    

    输出:

    data{
        // This should all be tabbed 
        This is some text
        across multiple
        lines.
    }
    

    【讨论】:

    • 我不想标记原始字符串,并且在任何地方使用\t 构造会很快破坏可读性。这就是我使用dedent 的原因
    • 编辑使用join()splitlines()
    猜你喜欢
    • 2017-06-24
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2019-05-22
    • 1970-01-01
    • 2021-07-15
    • 1970-01-01
    相关资源
    最近更新 更多