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 nie są takie 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.