web-dev-qa-db-ja.com

Pythonには、複数行の文字列をインデント解除するための組み込み関数がありますか?

文字列があるとしましょう

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 @"
44
Hubro

組み込み関数ではなく、標準ライブラリの関数 textwrap.dedent()

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

Controller = require 'controller'

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

    constructor: ->
        Controller.mix @
81
Sven Marnach

textwrap.dedent()は必要なものに近いですが、先頭に改行があるため、要求したものを実装していません。 dedentから先頭の改行を削除する関数でsをラップすることもできます。

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

ただし、textwrap.dedent()は、空白のみの行を特別な方法で処理します。これは、インデントの複数行ステートメントからPython sourceを生成する場合、末尾の空白は重要ではありません)。

ただし、一般に、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])
_
8
Anthon

この質問にはすでに回答済みですが、次の方法もあります。

import inspect

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

    return inspect.cleandoc(t)

print(test())
5
iSplasher