Jak podzielić ciąg wielu linii na wiele linii?


287

Mam wieloliniowy literał łańcuchowy, który chcę wykonać operację na każdej linii, na przykład:

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

Chcę zrobić coś takiego:

for line in inputString:
    doStuff()

Odpowiedzi:


437
inputString.splitlines()

Daje ci listę z każdym elementem, splitlines()metoda ma na celu podzielenie każdej linii na element listy.


12
+1. Myślę, że jest to ładniejsze niż przyjęte rozwiązanie, ponieważ nie zadziera wyraźnie z separatorem linii. Wszystko działa po prostu z dedykowaną metodą API!
lpapp

12
@lpapp, całkowicie się zgadzam. splitlines () jest semantycznie (i funkcjonalnie, ponieważ wykorzystuje uniwersalne znaki nowej linii i pomija końcową pustą linię) lepiej niż split ('\ n'). Wtedy (2008) Byłem tylko początkującym Pythonistą i grepping, chociaż moje skrypty pokazują teraz, że ja również używam splitline () prawie wyłącznie. Dlatego usuwam moją 104-punktową odpowiedź ( * szloch ... * ) i zamiast tego popieram tę.
efotinis

18
To także sprawia ''.splitlines() == [], że nie ['']tak jak w przypadku ''.split('\n').
prawej strony

198

Tak jak inni powiedzieli:

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

Jest to identyczne z powyższym, ale funkcje modułu łańcuchowego są przestarzałe i należy ich unikać:

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

Alternatywnie, jeśli chcesz, aby każda linia zawierała sekwencję przerwania (CR, LF, CRLF), użyj splitlinesmetody z Trueargumentem:

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

12
Działa to tylko w systemach, które używają „\ n” jako terminatora linii.
Jeremy Cantrell

20
@Jeremy: Cytowane literały łańcuchowe zawsze używają EOL '\ n', niezależnie od platformy. Podobnie czyta się pliki w trybie tekstowym.
efotinis

16
inputString.split(os.linesep)użyje terminatora linii specyficznego dla platformy.
James

10
Dziwne, że ta odpowiedź jest tak pozytywna. Twarde kodowanie „\ n” jest złym pomysłem, ale nawet jeśli użyjesz os.linesep zamiast tego, będziesz mieć problemy z końcami linii systemu Windows w Linuksie i odwrotnie itp. Ponadto promuje linie podziału z argumentem True, który jest prawdopodobnie mniej powszechny sposób korzystania z niego ...
lpapp

4
Połączenie metody suboptymalnej, przestarzałej metody i redundantnej odmiany metody optymalnej.
jwg

50

Zastosowaniestr.splitlines() .

splitlines()poprawnie obsługuje nowe wiersze, w przeciwieństwie do split("\n").

Ma również tę zaletę, o której wspomina @efotinis, polegającą na opcjonalnym włączeniu znaku nowej linii w wyniku podziału, gdy zostanie wywołany z Trueargumentem.


Szczegółowe wyjaśnienie, dlaczego nie należy używać split("\n"):

\n, w Pythonie reprezentuje uniksowy podział linii (kod dziesiętny ASCII 10), niezależnie od platformy, na której jest uruchamiany. Jednak reprezentacja podziału linii zależy od platformy . W systemie Windows \nma dwa znaki CRi LF(kody dziesiętne ASCII 13 i 10, AKA \ri \n), natomiast w każdym nowoczesnym systemie Unix (w tym OS X) jest to pojedynczy znak LF.

print, na przykład działa poprawnie, nawet jeśli masz ciąg z zakończeniami linii, które nie pasują do Twojej platformy:

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

Jednak wyraźne podzielenie na „\ n” spowoduje zachowanie zależne od platformy:

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

Nawet jeśli go użyjesz os.linesep, zostanie on podzielony tylko zgodnie z separatorem nowej linii na Twojej platformie i zakończy się niepowodzeniem, jeśli przetwarzasz tekst utworzony na innych platformach lub z czystym \n:

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

splitlines rozwiązuje wszystkie te problemy:

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

Odczytywanie plików w trybie tekstowym częściowo łagodzi problem z reprezentacją nowej linii, ponieważ konwertuje Pythona w nową \nlinię platformy. Jednak tryb tekstowy istnieje tylko w systemie Windows. W systemach Unix wszystkie pliki są otwierane w trybie binarnym, więc użycie split('\n')w systemie UNIX z plikiem Windows spowoduje niepożądane zachowanie. Ponadto nie jest niczym niezwykłym przetwarzanie ciągów znaków z potencjalnie różnymi znakami nowej linii z innych źródeł, takich jak gniazdo.


Porównanie nie jest sprawiedliwe, ponieważ można również użyć split (os.linesep), aby uniknąć specyficznego dla platformy bitu.
lpapp

6
Uwaga @lpapp, która splitlineszostanie podzielona na dowolnym zakończeniu linii. split(os.linesep)zawiedzie podczas odczytu pliku systemu Windows w systemie Unix, na przykład
goncalopp

1
Kolejny powód korzystania z linii podziału w moim przypadku, dzięki. Dałem +1. Osobiście włączyłbym nawet te informacje w komentarzach do twojej odpowiedzi.
lpapp

20

W tym konkretnym przypadku może to być przesada, ale inna opcja wymaga użycia StringIOdo utworzenia obiektu podobnego do pliku

for line in StringIO.StringIO(inputString):
    doStuff()

Tak, jest to najbardziej idiomatyczne, najbardziej Pythonowe podejście.
Paramagnetyczny rogalik

4
Zaletą tej metody w porównaniu z tym str.split, że nie wymaga alokacji pamięci (odczytuje ciąg w miejscu). Wadą jest to, że jest znacznie wolniejszy, jeśli używaszStringIO (około 50x). Jeśli jednak użyjesz cStringIO, jest około dwa razy szybszy
goncalopp

2x szybciej niż co?
Irina Rapoport

1
@IrinaRapoport, cStringIO jest 2x szybszy niż StringIO
iruvar

1

Pierwotny post zażądał kodu, który drukuje niektóre wiersze (jeśli są prawdziwe dla niektórych warunków) plus następny wiersz. Moja implementacja będzie następująca:

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

0

Chciałbym, aby komentarze miały odpowiednie formatowanie tekstu, ponieważ uważam, że odpowiedź @ 1_CR wymaga więcej nierówności i chciałbym rozszerzyć jego odpowiedź. W każdym razie poprowadził mnie do następującej techniki; użyje cStringIO, jeśli jest dostępny (ALE UWAGA: cStringIO i StringIO nietakie same , ponieważ nie można podklasować cStringIO ... to jest wbudowany ... ale dla podstawowych operacji składnia będzie identyczna, więc możesz to zrobić ):

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

for line in StringIO.StringIO(variable_with_multiline_string):
    pass
print line.strip()
Korzystając z naszej strony potwierdzasz, że przeczytałeś(-aś) i rozumiesz nasze zasady używania plików cookie i zasady ochrony prywatności.
Licensed under cc by-sa 3.0 with attribution required.