2013-08-29 6 views
6

Ich möchte alle Zeilen einer mehrzeiligen Zeichenfolge mit Ausnahme der ersten einrücken, ohne den Text zu umbrechen.Python: Alle Zeilen einer Zeichenkette einrücken, außer bei ersten Zeilenumbrüchen?

Zum Beispiel möchte ich mich wenden:

A very very very very very very very very very very very very very very very very 
long mutiline 
string 

in:

A very very very very very very very very very very very very very very very very 
    long multiline 
    string 

Ich habe

versucht
textwrap.fill(string, width=999999999999, subsequent_indent=' ',) 

Aber das bringt noch den gesamten Text auf einer Linie. Gedanken?

+0

Aus der Dokumentation für 'sequential_indent':" Zeichenfolge, die allen Zeilen der umbrochenen Ausgabe vorangestellt wird. " Da nichts eingepackt wird, wird nichts eingerückt. –

Antwort

12

Sie müssen nur das Newline-Zeichen '\n' mit einem neuen Linie Charakter und die weißen Flächen '\n    ' und es zu einer Variablen speichern, ersetzen (da replace wird Ihre ursprüngliche Zeichenfolge nicht ändern, aber eine neue mit den Ersetzungen zurückgeben).

string = string.replace('\n', '\n ') 
2

Meinen Sie so etwas wie dieses:

In [21]: s = 'abc\ndef\nxyz' 

In [22]: print s 
abc 
def 
xyz 

In [23]: print '\n '.join(s.split('\n')) 
abc 
    def 
    xyz 

?

edit: Alternativ (HT @ Steven Rumbalski):

In [24]: print s.replace('\n', '\n ') 
abc 
    def 
    xyz 
+3

Warum 'split' und' join' wenn man einfach 'ersetzen' kann? –

+1

@ DavidY.Stephenson: Es wäre unpythonisch, 'textwrap' für einen Job zu verwenden, der kein Wrapping benötigt. –

0

Die bloße ersetzen erwähnt durch @steven-rumbalski wird der effizienteste Weg, um dies zu erreichen, aber es ist nicht der einzige Weg.

Hier ist eine andere Lösung mit List Comprehensions. Wenn der Text bereits in eine Liste von Zeilen aufgeteilt wurde, wird dies viel schneller als Laufen join(), replace() und splitlines()

text = """A very very very very very very very very very very very very very very very very 
long mutiline 
string""" 

lines = text.splitlines() 
indented = [' ' + l for l in lines] 
indented[0] = lines[0] 
indented = '\n'.join(indented) 

Die Liste geändert anstelle werden könnte, aber es gibt ein deutlich Leistungs Kosten einen zweiten im Vergleich mit Variable. Es ist auch mäßig schneller, alle Zeilen einzurücken und dann die erste Zeile in einer anderen Operation auszuwechseln.

Es gibt auch das Modul textwrap. Ich stimme nicht zu, dass die Verwendung von textwrap für den Einzug unpythonisch ist. Wenn die Linien in einer einzelnen Zeichenfolge mit Zeilenumbrüchen verknüpft sind, ist diese Zeichenfolge in sich eingeschlossen. Einrückung ist eine logische Erweiterung der Textumhüllung, so dass Textumwicklung für mich sinnvoll ist.

Außer dass es langsam ist. Wirklich, wirklich langsam. Wie 15x langsamer.

Python 3 hinzugefügt indent zu textwrap, die Einrückung ohne Umwicklung sehr einfach macht. Es gibt sicherlich eine elegantere Art, mit dem Lambda-Prädikat umzugehen, aber das tut genau das, wonach die ursprüngliche Frage gefragt war.

indented = textwrap.indent(text, ' ', lambda x: not text.splitlines()[0] in x) 

Hier sind einige timeit Ergebnisse der verschiedenen Methoden.

>>> timeit.timeit(r"text.replace('\n', '\n ')", setup='text = """%s"""' % text) 
0.5123521030182019 

Die beiden Liste Verständnis Lösungen:

>>> timeit.timeit(r"indented = [' ' + i for i in lines]; indented[0] = lines[0]", setup='lines = """%s""".splitlines()' % text) 
0.7037646849639714 

>>> timeit.timeit(r"indented = [lines[0]] + [' ' + i for i in lines[1:]]", setup='lines = """%s""".splitlines()' % text) 
1.0310905870283023 

Und hier ist das unglückliche textwrap Ergebnis:

>>> timeit.timeit(r"textwrap.indent(text, ' ', lambda x: not text.splitlines()[0] in x)", setup='import textwrap; text = """%s"""' % text) 
7.7950868209591135 

Ich dachte, einige jener Zeit die schrecklich ineffizient Prädikat sein könnte, aber auch mit das entfernt, textwrap.indent ist immer noch mehr als 8 mal langsamer als eine bloße Ersetzung.

>>> timeit.timeit(r"textwrap.indent(text, ' ')", setup='import textwrap; text = """%s"""' % text) 
4.266149697010405