Como remover o recuo extra de strings multi-linhas citadas em Python?
Pergunta
Eu tenho um editor do Python onde o usuário está inserindo um script ou código, que é colocado em um método principal nos bastidores, além de ter todas as linhas recuadas. O problema é que, se um usuário tiver uma string multi -linha, o recuo feito em todo o script afeta a string, inserindo uma guia em todos os espaço. Um script de problema seria algo tão simples como:
"""foo
bar
foo2"""
Então, quando no método principal seria:
def main():
"""foo
bar
foo2"""
E a string agora teria uma guia extra no início de todas as linhas.
Solução
Portanto, se eu o obtiver corretamente, você pega as que o usuário entra, recupere -o corretamente e adicione -o ao restante do seu programa (e execute todo esse programa).
Então, depois de colocar a entrada do usuário em seu programa, você pode executar um regex, que basicamente leva esse recuo forçado de volta. Algo como: Dentro de três citações, substitua todos os "novos marcadores de linha" seguidos por quatro espaços (ou uma guia) por apenas um "novo marcador de linha".
Outras dicas
textwrap.dedent A partir da biblioteca padrão, existe para desfazer automaticamente o recuo maluco.
Pelo que vejo, uma resposta melhor aqui pode ser inspect.cleandoc
, que faz funcionalmente o que textwrap.dedent
mas também corrige os problemas que textwrap.dedent
tem com a linha principal. O exemplo abaixo mostra as diferenças:
>>> 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'
O que se segue à primeira linha de uma corda multilina faz parte da string e não é tratada como indentação pelo analisador. Você pode escrever livremente:
def main():
"""foo
bar
foo2"""
pass
E isso fará a coisa certa.
Por outro lado, isso não é legível, e Python sabe disso. Então, se um docstring contém espaço em branco em seu segundo linha, essa quantidade de espaço em branco é despojada quando você usa help()
para ver o docstring. Desta forma, help(main)
e o abaixo help(main2)
produzir as mesmas informações de ajuda.
def main2():
"""foo
bar
foo2"""
pass
A única maneira que vejo - é tirar as primeiras guias N para cada linha que começa com a segunda, onde n é a identificação conhecida do método principal.
Se essa identificação não for conhecida de antemão - você pode adicionar a Newline à direita antes de inseri -la e desmaiar o número de guias da última linha ...
A terceira solução é analisar os dados e encontrar o início da cotação multilina e não adicionar sua identificação a todas as linhas depois que ela será fechada.
Acho que há uma solução melhor ..