Wie teile ich eine mehrzeilige Zeichenfolge in mehrere Zeilen auf?

287

Ich habe ein mehrzeiliges Zeichenfolgenliteral, mit dem ich in jeder Zeile eine Operation ausführen möchte, wie folgt:

inputString = """Line 1
Line 2
Line 3"""

Ich möchte so etwas wie das Folgende tun:

for line in inputString:
    doStuff()
Bradtgmurray
quelle

Antworten:

437
inputString.splitlines()

Wenn Sie eine Liste mit jedem Element erhalten, ist die splitlines()Methode so konzipiert, dass jede Zeile in ein Listenelement aufgeteilt wird.

UnkwnTech
quelle
12
+1. Ich denke, das ist schöner als die akzeptierte Lösung, weil es nicht explizit mit dem Zeilentrennzeichen in Konflikt gerät. Es funktioniert alles nur mit einer dedizierten API-Methode!
lpapp
12
@lpapp, ich stimme vollkommen zu. splitlines () ist semantisch (und funktional, da es universelle Zeilenumbrüche verwendet und eine nachgestellte leere Zeile weglässt) besser als split ('\ n'). Damals (2008) war ich nur ein Pythonista-Neuling und greifend, obwohl meine Skripte jetzt zeigen, dass auch ich fast ausschließlich splitlines () verwende. Ich lösche daher meine 104-Punkte-Antwort ( * schluchz ... * ) und werde diese stattdessen unterstützen.
Efotinis
18
Dies macht ''.splitlines() == []auch nicht ['']wie bei ''.split('\n').
Rechtsfalte
198

Wie die anderen sagten:

inputString.split('\n')  # --> ['Line 1', 'Line 2', 'Line 3']

Dies ist identisch mit dem oben genannten, aber die Funktionen des String-Moduls sind veraltet und sollten vermieden werden:

import string
string.split(inputString, '\n')  # --> ['Line 1', 'Line 2', 'Line 3']

Wenn Sie alternativ möchten, dass jede Zeile die Unterbrechungssequenz (CR, LF, CRLF) enthält, verwenden Sie alternativ die splitlinesMethode mit einem TrueArgument:

inputString.splitlines(True)  # --> ['Line 1\n', 'Line 2\n', 'Line 3']
efotinis
quelle
12
Dies funktioniert nur auf Systemen, die '\ n' als Zeilenabschluss verwenden.
Jeremy Cantrell
20
@Jeremy: String-Literale mit dreifachen Anführungszeichen verwenden unabhängig von der Plattform immer eine '\ n' EOL. Dateien werden auch im Textmodus gelesen.
Efotinis
16
inputString.split(os.linesep)verwendet den plattformspezifischen Leitungsabschluss.
James
10
Es ist seltsam, dass diese Antwort so positiv bewertet wird. Hardcodierung '\ n' ist eine schlechte Idee, aber selbst wenn Sie stattdessen os.linesep verwenden, treten Probleme mit Windows-Zeilenenden unter Linux auf und umgekehrt usw. Darüber hinaus werden Splitlines mit True-Argument gefördert wahrscheinlich die weniger verbreitete Art, es zu benutzen ...
lpapp
4
Eine Kombination aus einer suboptimalen Methode, einer veralteten Methode und einer redundanten Variation der optimalen Methode.
JWG
50

Verwenden Siestr.splitlines() .

splitlines()behandelt Zeilenumbrüche im Gegensatz zu split("\n").

Es hat auch den von @efotinis erwähnten Vorteil, dass das Zeilenumbruchzeichen optional in das Teilungsergebnis aufgenommen wird, wenn es mit einem TrueArgument aufgerufen wird .


Detaillierte Erklärung, warum Sie nicht verwenden sollten split("\n"):

\nstellt in Python einen Unix-Zeilenumbruch (ASCII-Dezimalcode 10) dar, unabhängig von der Plattform, auf der Sie ihn ausführen. Die Darstellung des Zeilenumbruchs ist jedoch plattformabhängig . Unter Windows sind \nes zwei Zeichen CRund LF(ASCII-Dezimalcodes 13 und 10, AKA \rund \n), während es unter jedem modernen Unix (einschließlich OS X) das einzelne Zeichen ist LF.

printFunktioniert beispielsweise auch dann ordnungsgemäß, wenn Sie eine Zeichenfolge mit Zeilenenden haben, die nicht zu Ihrer Plattform passen:

>>> print " a \n b \r\n c "
 a 
 b 
 c

Eine explizite Aufteilung auf "\ n" führt jedoch zu einem plattformabhängigen Verhalten:

>>> " a \n b \r\n c ".split("\n")
[' a ', ' b \r', ' c ']

Selbst wenn Sie verwenden os.linesep, wird es nur gemäß dem Zeilenumbruchtrennzeichen auf Ihrer Plattform aufgeteilt und schlägt fehl, wenn Sie Text verarbeiten, der auf anderen Plattformen erstellt wurde, oder mit einem bloßen \n:

>>> " a \n b \r\n c ".split(os.linesep)
[' a \n b ', ' c ']

splitlines löst all diese Probleme:

>>> " a \n b \r\n c ".splitlines()
[' a ', ' b ', ' c ']

Durch das Lesen von Dateien im Textmodus wird das Problem der Zeilenumbruchdarstellung teilweise verringert, da Pythons \nin die Zeilenumbruchdarstellung der Plattform konvertiert werden. Der Textmodus ist jedoch nur unter Windows verfügbar. Auf Unix-Systemen werden alle Dateien im Binärmodus geöffnet. Die Verwendung split('\n')in einem UNIX-System mit einer Windows-Datei führt daher zu unerwünschtem Verhalten. Es ist auch nicht ungewöhnlich, Zeichenfolgen mit möglicherweise unterschiedlichen Zeilenumbrüchen aus anderen Quellen zu verarbeiten, z. B. aus einem Socket.

Goncalopp
quelle
Der Vergleich ist nicht fair, da Sie auch split (os.linesep) verwenden können, um das plattformspezifische Bit zu vermeiden.
lpapp
6
@ lpapp Hinweis, splitlinesder an jedem Zeilenende geteilt wird. split(os.linesep)wird zum Beispiel beim Lesen einer Windows-Datei unter Unix
fehlschlagen
1
Ein weiterer Grund für die Verwendung von Splitlines in meinem Fall, danke. Ich gab eine +1. Ich persönlich würde die Informationen sogar in Kommentare in Ihre Antwort aufnehmen.
lpapp
20

Könnte in diesem speziellen Fall übertrieben sein, aber eine andere Option besteht StringIOdarin, ein dateiähnliches Objekt zu erstellen

for line in StringIO.StringIO(inputString):
    doStuff()
iruvar
quelle
Ja, dies ist der idiomatischste und pythonischste Ansatz.
Das paramagnetische Croissant
4
Ein Vorteil dieser Methode im Vergleich zu str.splitist , dass kein Speicher zugewiesen werden muss (sie liest die Zeichenfolge an Ort und Stelle). Ein Nachteil ist, dass es viel langsamer ist, wenn Sie verwendenStringIO (ca. 50x). Wenn Sie cStringIOjedoch verwenden, ist es etwa 2x schneller
Goncalopp
2x schneller als was?
Irina Rapoport
1
@ IrinaRapoport, cStringIO ist 2x schneller als StringIO
iruvar
1

Der ursprüngliche Beitrag forderte Code an, der einige Zeilen druckt (sofern sie für eine bestimmte Bedingung zutreffen), sowie die folgende Zeile. Meine Implementierung wäre folgende:

text = """1 sfasdf
asdfasdf
2 sfasdf
asdfgadfg
1 asfasdf
sdfasdgf
"""

text = text.splitlines()
rows_to_print = {}

for line in range(len(text)):
    if text[line][0] == '1':
        rows_to_print = rows_to_print | {line, line + 1}

rows_to_print = sorted(list(rows_to_print))

for i in rows_to_print:
    print(text[i])
Finrod Felagund
quelle
0

Ich wünschte, Kommentare hätten die richtige Code-Text-Formatierung, da ich denke, dass die Antwort von @ 1_CR mehr Unebenheiten erfordert, und ich möchte seine Antwort ergänzen. Wie auch immer, er führte mich zu der folgenden Technik; Wenn verfügbar, wird cStringIO verwendet (ABER HINWEIS: cStringIO und StringIO sind nicht identisch , da Sie cStringIO nicht unterordnen können ... es ist integriert ... aber für grundlegende Operationen ist die Syntax identisch, sodass Sie dies tun können ):

try:
    import cStringIO
    StringIO = cStringIO
except ImportError:
    import StringIO

for line in StringIO.StringIO(variable_with_multiline_string):
    pass
print line.strip()
Mike S.
quelle