How to remove extra indentation of Python triple quoted multi-line strings?

后端 未结 6 1005
野的像风
野的像风 2020-12-23 14:46

I have a python editor where the user is entering a script or code, which is then put into a main method behind the scenes, while also having every line indented. The proble

相关标签:
6条回答
  • 2020-12-23 14:59

    The only way i see - is to strip first n tabs for each line starting with second, where n is known identation of main method.

    If that identation is not known beforehand - you can add trailing newline before inserting it and strip number of tabs from the last line...

    The third solution is to parse data and find beginning of multiline quote and do not add your identation to every line after until it will be closed.

    Think there is a better solution..

    0 讨论(0)
  • 2020-12-23 15:02

    Showing the difference between textwrap.dedent and inspect.cleandoc with a little more clarity:

    Behavior with the leading part not indented

    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)))
    

    Output

    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'
    

    Behavior with the leading part indented

    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)))
    

    Output

    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 讨论(0)
  • 2020-12-23 15:05

    textwrap.dedent from the standard library is there to automatically undo the wacky indentation.

    0 讨论(0)
  • 2020-12-23 15:09

    So if I get it correctly, you take whatever the user inputs, indent it properly and add it to the rest of your program (and then run that whole program).

    So after you put the user input into your program, you could run a regex, that basically takes that forced indentation back. Something like: Within three quotes, replace all "new line markers" followed by four spaces (or a tab) with only a "new line marker".

    0 讨论(0)
  • 2020-12-23 15:13

    What follows the first line of a multiline string is part of the string, and not treated as indentation by the parser. You may freely write:

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

    and it will do the right thing.

    On the other hand, that's not readable, and Python knows it. So if a docstring contains whitespace in it's second line, that amount of whitespace is stripped off when you use help() to view the docstring. Thus, help(main) and the below help(main2) produce the same help info.

    def main2():
        """foo
        bar
        foo2"""
        pass
    
    0 讨论(0)
  • 2020-12-23 15:15

    From what I see, a better answer here might be inspect.cleandoc, which does much of what textwrap.dedent does but also fixes the problems that textwrap.dedent has with the leading line.

    The below example shows the differences:

    >>> 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'
    >>> z = """\tfoo
    bar\tbaz
    """
    >>> textwrap.dedent(z)
    '\tfoo\nbar\tbaz\n'
    >>> inspect.cleandoc(z)
    'foo\nbar     baz'
    

    Note that inspect.cleandoc also expands internal tabs to spaces. This may be inappropriate for one's use case, but works fine for me.

    0 讨论(0)
提交回复
热议问题