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()
bradtgmurray
źródło

Odpowiedzi:

437
inputString.splitlines()

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

UnkwnTech
źródło
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']
efotinis
źródło
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.

goncalopp
źródło
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()
iruvar
źródło
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])
Finrod Felagund
źródło
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()
Mike S.
źródło