Comment diviser une chaîne multi-lignes en plusieurs lignes?

287

J'ai un littéral de chaîne multi-lignes que je veux faire une opération sur chaque ligne, comme ceci:

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

Je veux faire quelque chose comme ceci:

for line in inputString:
    doStuff()
bradtgmurray
la source

Réponses:

438
inputString.splitlines()

Vous donnera une liste avec chaque élément, la splitlines()méthode est conçue pour diviser chaque ligne en un élément de liste.

UnkwnTech
la source
12
+1. Je pense que c'est plus agréable que la solution acceptée car elle ne dérange pas explicitement avec le séparateur de ligne. Tout fonctionne avec une méthode API dédiée!
lpapp
12
@lpapp, je suis totalement d'accord. splitlines () est sémantiquement (et fonctionnellement, car il utilise des sauts de ligne universels et omet une ligne vide de fin) mieux que split ('\ n'). À l'époque (2008), j'étais juste un débutant Pythonista et je saluais bien que mes scripts montrent maintenant que moi aussi j'utilise splitlines () presque exclusivement. Je supprime donc ma réponse en 104 points ( * sob ... * ) et j'approuverai celle-ci à la place.
efotinis
18
Cela fait aussi ''.splitlines() == [], pas ['']comme avec ''.split('\n').
plié à droite
198

Comme les autres l'ont dit:

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

Ceci est identique à ce qui précède, mais les fonctions du module de chaîne sont obsolètes et doivent être évitées:

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

Alternativement, si vous voulez que chaque ligne inclue la séquence de coupure (CR, LF, CRLF), utilisez la splitlinesméthode avec un Trueargument:

inputString.splitlines(True)  # --> ['Line 1\n', 'Line 2\n', 'Line 3']
efotinis
la source
12
Cela ne fonctionnera que sur les systèmes qui utilisent «\ n» comme terminateur de ligne.
Jeremy Cantrell
20
@Jeremy: les littéraux de chaîne entre guillemets triples utilisent toujours un EOL '\ n', quelle que soit la plate-forme. Les fichiers sont également lus en mode texte.
efotinis
16
inputString.split(os.linesep)utilisera le terminateur de ligne spécifique à la plate-forme.
James
10
Il est étrange que cette réponse soit si positive. Le codage en dur '\ n' est une mauvaise idée, mais même si vous utilisez os.linesep au lieu de cela, vous aurez des problèmes avec les extrémités de ligne Windows sous Linux et vice versa, etc. probablement la façon la moins courante de l'utiliser ...
lpapp
4
Combinaison d'une méthode sous-optimale, d'une méthode déconseillée et d'une variation redondante de la méthode optimale.
jwg
50

Utilisezstr.splitlines() .

splitlines()gère les sauts de ligne correctement, contrairement à split("\n").

Il présente également l'avantage mentionné par @efotinis d'inclure éventuellement le caractère de nouvelle ligne dans le résultat de division lorsqu'il est appelé avec un Trueargument.


Explication détaillée des raisons pour lesquelles vous ne devez pas utiliser split("\n"):

\n, en Python, représente un saut de ligne Unix (code décimal ASCII 10), indépendamment de la plateforme sur laquelle vous l'exécutez. Cependant, la représentation de saut de ligne dépend de la plateforme . Sur Windows, il \ny a deux caractères CRet LF(codes décimaux ASCII 13 et 10, AKA \ret \n), tandis que sur tout Unix moderne (y compris OS X), c'est le seul caractère LF.

print, par exemple, fonctionne correctement même si vous avez une chaîne dont les fins de ligne ne correspondent pas à votre plate-forme:

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

Cependant, un fractionnement explicite sur "\ n" produira un comportement dépendant de la plateforme:

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

Même si vous l'utilisez os.linesep, il ne se divisera qu'en fonction du séparateur de nouvelle ligne sur votre plate-forme et échouera si vous traitez du texte créé sur d'autres plates-formes, ou avec un nu \n:

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

splitlines résout tous ces problèmes:

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

La lecture de fichiers en mode texte atténue partiellement le problème de représentation de nouvelle ligne, car il convertit Python \nen représentation de nouvelle ligne de la plate-forme. Cependant, le mode texte n'existe que sur Windows. Sur les systèmes Unix, tous les fichiers sont ouverts en mode binaire, donc l'utilisation split('\n')dans un système UNIX avec un fichier Windows entraînera un comportement indésirable. De plus, il n'est pas inhabituel de traiter des chaînes avec des sauts de ligne potentiellement différents à partir d'autres sources, comme à partir d'un socket.

goncalopp
la source
La comparaison n'est pas juste car vous pouvez également utiliser le fractionnement (os.linesep) pour éviter le bit spécifique à la plate-forme.
lpapp
6
@lpapp note qui splitlinesse divisera à toute fin de ligne. split(os.linesep)échouera lors de la lecture d'un fichier Windows sous Unix, par exemple
goncalopp
1
Une autre raison d'utiliser des splitlines dans mon cas, merci. J'ai donné un +1. Personnellement, j'intégrerais même les informations dans les commentaires dans votre réponse.
lpapp
20

Peut être exagéré dans ce cas particulier, mais une autre option consiste à utiliser StringIOpour créer un objet de type fichier

for line in StringIO.StringIO(inputString):
    doStuff()
iruvar
la source
Oui, c'est l'approche la plus idiomatique et la plus Python-ic.
The Paramagnetic Croissant
4
Un avantage de cette méthode, par rapport à str.split, n'est pas nécessaire d'allouer de la mémoire (il lit la chaîne en place). Un inconvénient est que c'est beaucoup plus lent si vous utilisezStringIO (environ 50x). Si vous utilisez cStringIO, cependant, c'est environ 2x plus rapide
goncalopp
2x plus rapide que quoi?
Irina Rapoport
1
@IrinaRapoport, cStringIO est 2x plus rapide que StringIO
iruvar
1

Le message d'origine a demandé du code qui imprime certaines lignes (si elles sont vraies pour certaines conditions) plus la ligne suivante. Ma mise en œuvre serait la suivante:

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
la source
0

Je souhaite que les commentaires aient un formatage de texte de code approprié, car je pense que la réponse de @ 1_CR a besoin de plus de bosses, et je voudrais augmenter sa réponse. Quoi qu'il en soit, il m'a conduit à la technique suivante; il utilisera cStringIO s'il est disponible (MAIS NOTE: cStringIO et StringIO ne sont pas identiques , car vous ne pouvez pas sous-classer cStringIO ... c'est un intégré ... mais pour les opérations de base la syntaxe sera identique, donc vous pouvez le faire ):

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

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