web-dev-qa-db-ja.com

Python三重引用符で囲まれた複数行の文字列の余分なインデントを削除する方法は?

私はpythonエディターを使用して、ユーザーがスクリプトまたはコードを入力し、それを舞台裏でメインメソッドに挿入しますが、すべての行をインデントします。問題は、ユーザーが複数行の文字列があり、スクリプト全体に行われたインデントは、すべてのスペースにタブを挿入することにより、文字列に影響を与えます。問題のあるスクリプトは、次のように単純なものになります。

"""foo
bar
foo2"""

したがって、メインメソッドでは次のようになります。

def main():
    """foo
    bar
    foo2"""

文字列には、すべての行の先頭に追加のタブがあります。

55
Mike

textwrap.dedent 標準ライブラリの奇妙なインデントを自動的に元に戻すためにあります。

103
thraxil

私が見るものから、ここでより良い答えはinspect.cleandoc、機能的に何をするかtextwrap.dedentは実行しますが、textwrap.dedentは先頭行にあります。

以下の例は違いを示しています:

   >>> import textwrap
   >>> import inspect
   >>> x = """foo bar
       baz
       foobar
       foobaz
       """
   >>> inspect.cleandoc(x)
   'foo bar\nbaz\nfoobar\nfoobaz'
   >>> textwrap.dedent(x)
   'foo bar\n    baz\n    foobar\n    foobaz\n'
   >>> y = """
   ...     foo
   ...     bar
   ... """
   >>> textwrap.dedent(y)
   '\nfoo\nbar\n'
   >>> inspect.cleandoc(y)
   'foo\nbar'
28
bbenne10

複数行の文字列の最初の行に続くものは文字列の一部であり、パーサーではインデントとして扱われません。あなたは自由に書くことができます:

_def main():
    """foo
bar
foo2"""
    pass
_

そしてそれは正しいことをします。

一方、それは読みにくく、Pythonはそれを知っています。そのため、docstringにsecond行に空白が含まれている場合、その量の空白は、 docstringを表示するにはhelp()を使用します。したがって、help(main)と以下のhelp(main2)は同じヘルプ情報を生成します。

_def main2():
    """foo
    bar
    foo2"""
    pass
_

私が見る唯一の方法-2番目から始まる各行の最初のn個のタブを取り除くことです。ここで、nはメインメソッドの既知のIDです。

その識別が事前にわからない場合-挿入する前に末尾の改行を追加し、最後の行からタブの数を取り除くことができます...

3番目の解決策は、データを解析して複数行の引用の始まりを見つけ、閉じられるまですべての行にIDを追加しないことです。

より良い解決策があると思います。

1

textwrap.dedentinspect.cleandocの違いをもう少し明確に示す:

先頭部分がインデントされていない動作

import textwrap
import inspect

string1="""String
with
no indentation
       """
string2="""String
        with
        indentation
       """
print('string1 plain=' + repr(string1))
print('string1 inspect.cleandoc=' + repr(inspect.cleandoc(string1)))
print('string1 texwrap.dedent=' + repr(textwrap.dedent(string1)))
print('string2 plain=' + repr(string2))
print('string2 inspect.cleandoc=' + repr(inspect.cleandoc(string2)))
print('string2 texwrap.dedent=' + repr(textwrap.dedent(string2)))

出力

string1 plain='String\nwith\nno indentation\n       '
string1 inspect.cleandoc='String\nwith\nno indentation\n       '
string1 texwrap.dedent='String\nwith\nno indentation\n'
string2 plain='String\n        with\n        indentation\n       '
string2 inspect.cleandoc='String\nwith\nindentation'
string2 texwrap.dedent='String\n        with\n        indentation\n'

先頭部分がインデントされた動作

string1="""
String
with
no indentation
       """
string2="""
        String
        with
        indentation
       """

print('string1 plain=' + repr(string1))
print('string1 inspect.cleandoc=' + repr(inspect.cleandoc(string1)))
print('string1 texwrap.dedent=' + repr(textwrap.dedent(string1)))
print('string2 plain=' + repr(string2))
print('string2 inspect.cleandoc=' + repr(inspect.cleandoc(string2)))
print('string2 texwrap.dedent=' + repr(textwrap.dedent(string2)))

出力

string1 plain='\nString\nwith\nno indentation\n       '
string1 inspect.cleandoc='String\nwith\nno indentation\n       '
string1 texwrap.dedent='\nString\nwith\nno indentation\n'
string2 plain='\n        String\n        with\n        indentation\n       '
string2 inspect.cleandoc='String\nwith\nindentation'
string2 texwrap.dedent='\nString\nwith\nindentation\n'
0
codeforester