繁体   English   中英

Python 是否具有用于取消缩进多行字符串的内置函数?

[英]Does Python have a built-in function for unindenting a multiline string?

说我有字符串

s = """
    Controller = require 'controller'

    class foo
        view: 'baz'
        class: 'bar'

        constructor: ->
            Controller.mix @
"""

字符串中的每一行现在都有一个全局 4 个空格缩进。 如果这个字符串是在函数内部声明的,它将有一个 8 个空格的全局缩进,等等。

Python 有去除字符串全局左缩进的函数吗?

我希望该函数输出为:

Controller = require 'controller'

class foo
    view: 'baz'
    class: 'bar'

    constructor: ->
        Controller.mix @"

不是内置函数,而是标准库中的函数: textwrap.dedent()

>>> print(textwrap.dedent(s))

Controller = require 'controller'

class foo
    view: 'baz'
    class: 'bar'

    constructor: ->
        Controller.mix @

我知道这个问题已经得到了回答,但也有这种方式:

import inspect

def test():
    t = """
    some text
    """

    return inspect.cleandoc(t)

print(test())

textwrap.dedent()接近你想要的,但它没有实现你的要求,因为它有一个前导换行符。 您可以将dedent包装在从s dedent前导换行符的函数中:

def my_dedent(string):
    if string and string[0] == '\n':
        string = string[1:]
    return textwrap.dedent(string)

但是textwrap.dedent()以特殊方式处理只有空格的行,如果您从缩进多行语句生成 Python 源代码,那么尾随空格无关紧要。

但总的来说, textwrap.dedent()从比“最大缩进”更多空白的行中删除额外的空白,从所有空白行中删除空白,并在关闭"""之前删除任何空白,这是不合适的,尤其是因为这种行为未记录并使用非透明正则表达式完成

由于我还生成了空格通常很重要的非 Python 源代码,因此我使用以下例程。 它不处理 TAB 缩进,但它确实为您提供了不带换行符的输出,其中textwrap.dedent()失败。

def remove_leading_spaces(s, strict=False):
    '''Remove the maximum common spaces from all non-empty lines in string

Typically used to remove leading spaces from all non-empty lines in a
multiline string, preserving all extra spaces.
A leading newline (when not useing '"""\') is removed unless the strict
argument is True.

Note that if you want two spaces on the last line of the return value 
without a newline, you have to use the max indentation + 2 spaces before 
the closing """. If you just input 2 spaces that is likely to be the 
maximum indent.
    '''
    if s and not strict and s[0] == '\n':
        s = s[1:]
    lines = s.splitlines(True) # keep ends
    max_spaces = -1
    for line in lines:
        if line != '\n':
            for idx, c in enumerate(line[:max_spaces]):
                if not c == ' ':
                    break
            max_spaces = idx + 1
    return ''.join([l if l == '\n' else l[max_spaces-1:] for l in lines])

我能够通过回车来做到这一点:

s = """
    \r Controller = require 'controller'
    \r
    \rclass foo
    \r    view: 'baz'
    \r    class: 'bar'
    \r
    \r    constructor: ->
    \r        Controller.mix @
    \r"""

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM