58

说我有字符串

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 @"
4

4 回答 4

105

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

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

Controller = require 'controller'

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

    constructor: ->
        Controller.mix @
于 2012-06-22T13:24:35.153 回答
16

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

import inspect

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

    return inspect.cleandoc(t)

print(test())
于 2019-03-06T13:21:41.950 回答
9

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

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])
于 2013-03-17T12:55:09.593 回答
-1

我可以通过回车来做到这一点:

s = """
    \r Controller = require 'controller'
    \r
    \rclass foo
    \r    view: 'baz'
    \r    class: 'bar'
    \r
    \r    constructor: ->
    \r        Controller.mix @
    \r"""
于 2020-06-04T17:48:13.553 回答