Jak usunąć dodatkowe wcięcia w Pythonie Triple quoted multi-line strings?
Mam edytor Pythona, w którym użytkownik wprowadza skrypt lub kod, który jest następnie umieszczany w głównej metodzie za kulisami, jednocześnie mając każdą linię wciętą. Problem polega na tym, że jeśli użytkownik ma ciąg wielowierszowy, wcięcia wykonane w całym skrypcie wpływają na ciąg, wstawiając tabulator w każdej spacji. Skrypt problemowy byłby czymś tak prostym jak:
"""foo
bar
foo2"""
Więc gdy w głównej metodzie wyglądałoby to tak:
def main():
"""foo
bar
foo2"""
I ciąg będzie teraz mieć dodatkową kartę na początku każdej linii.
7 answers
Więc jeśli mam go poprawnie, bierzesz cokolwiek użytkownik wprowadza, wciąć go poprawnie i dodać go do reszty programu (a następnie uruchomić cały program).
Więc po wprowadzeniu danych użytkownika do programu, możesz uruchomić regex, który w zasadzie usuwa wymuszone wcięcia z powrotem. Coś w stylu: w ciągu trzech cudzysłowów, Zamień wszystkie "nowe znaczniki linii", a następnie cztery spacje (lub tabulator) na"nowy znacznik linii".
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2016-04-14 13:39:02
Texttwrap.dedent z biblioteki standardowej służy do automatycznego cofania dziwacznego wcięcia.
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2009-09-11 19:02:18
Z tego, co widzę, lepszą odpowiedzią może być inspect.cleandoc
, która robi wiele z tego, co robi textwrap.dedent
, ale także rozwiązuje problemy, które ma textwrap.dedent
z linią wiodącą.
Poniższy przykład pokazuje różnice:
>>> 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'
Zauważ, że inspect.cleandoc
rozszerza również wewnętrzne tabulatory na spacje.
To może być nieodpowiednie dla jednego przypadku użycia, ale działa dobrze dla mnie.
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2019-10-11 13:56:18
To, co następuje po pierwszej linii wielowierszowego łańcucha, jest jego częścią i nie jest traktowane jako wcięcie przez parser. Możesz swobodnie pisać:
def main():
"""foo
bar
foo2"""
pass
I zrobi to, co trzeba.
Z drugiej strony, to nie jest czytelne, a Python o tym wie. Jeśli więc docstring zawiera białe znaki w drugiej linii, ta ilość białych znaków jest usuwana, gdy używasz help()
do wyświetlania docstringu. Tak więc help(main)
i poniżej help(main2)
dają tę samą pomoc info.
def main2():
"""foo
bar
foo2"""
pass
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2018-07-06 13:35:11
Jedyny sposób jaki widzę-to rozebranie pierwszych n tabulatorów dla każdej linii zaczynającej się od drugiej, gdzie n jest znaną identyfikacją głównej metody.
Jeśli identyfikator nie jest wcześniej znany - możesz dodać końcową nową linię przed wstawieniem jej i usunąć liczbę tabulatorów z ostatniej linii...
Trzecim rozwiązaniem jest analiza danych i znalezienie początku cytatu wielowierszowego i nie dodawanie identyfikatora do każdej linii, dopóki nie zostanie ona zamknięta.
Think there is a better rozwiązanie..
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2009-09-11 18:16:09
Pokazując różnicę między textwrap.dedent
i inspect.cleandoc
z nieco większą klarownością:
Zachowanie z czołówką bez wcięcia
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)))
Wyjście
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'
Zachowanie z wciętą częścią wiodącą
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)))
Wyjście
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'
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2019-07-13 23:56:49
Chciałem zachować dokładnie to, co znajduje się pomiędzy wersami potrójnego cytowania, usuwając tylko wspólne wcięcie wiodące. Stwierdziłem, że texwrap.dedent
i inspect.cleandoc
nie zrobiły tego całkiem dobrze, więc napisałem ten. Używa os.path.commonprefix
.
import re
from os.path import commonprefix
def ql(s, eol=True):
lines = s.splitlines()
l0 = None
if lines:
l0 = lines.pop(0) or None
common = commonprefix(lines)
indent = re.match(r'\s*', common)[0]
n = len(indent)
lines2 = [l[n:] for l in lines]
if not eol and lines2 and not lines2[-1]:
lines2.pop()
if l0 is not None:
lines2.insert(0, l0)
s2 = "\n".join(lines2)
return s2
Może to zacytować dowolny ciąg znaków z dowolnym wcięciem. Chciałem, aby domyślnie zawierał kończący się nowy wiersz, ale z opcją usunięcia go, aby mógł ładnie cytować dowolny ciąg znaków.
Przykład:
print(ql("""
Hello
|\---/|
| o_o |
\_^_/
"""))
print(ql("""
World
|\---/|
| o_o |
\_^_/
"""))
Drugi ciąg ma 4 spacje wspólnego wcięcia, ponieważ końcowy """
jest wcięte mniej niż cytowany tekst:
Hello
|\---/|
| o_o |
\_^_/
World
|\---/|
| o_o |
\_^_/
Myślałem, że to będzie prostsze, inaczej nie zawracałbym sobie tym głowy!
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2021-01-24 09:01:04