ฉันจะแยกสตริงหลายบรรทัดเป็นหลายบรรทัดได้อย่างไร


287

ฉันมีสตริงตัวอักษรหลายบรรทัดที่ฉันต้องการดำเนินการในแต่ละบรรทัดเช่น:

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

ฉันต้องการทำสิ่งต่อไปนี้:

for line in inputString:
    doStuff()

คำตอบ:


437
inputString.splitlines()

จะให้รายการกับแต่ละรายการsplitlines()วิธีการออกแบบมาเพื่อแยกแต่ละบรรทัดเป็นองค์ประกอบรายการ


12
+1 ฉันคิดว่านี่ดีกว่าโซลูชันที่ยอมรับเพราะไม่ยุ่งกับตัวแยกบรรทัดอย่างชัดเจน ทุกอย่างทำงานร่วมกับวิธีการเฉพาะของ API!
lpapp

12
@lpapp ฉันเห็นด้วยอย่างยิ่ง splitlines () มีความหมาย (และใช้งานได้เนื่องจากมันใช้บรรทัดใหม่สากลและเว้นบรรทัดว่างไว้) ดีกว่า split ('\ n') ย้อนกลับไป (2008) ฉันเป็นแค่ Pythonista มือใหม่และตอนนี้ถึงแม้ว่าสคริปต์ของฉันจะแสดงให้เห็นว่าฉันก็ใช้ splitlines () เกือบจะเหมือนกัน ฉันจึงลบคำตอบ 104 จุดของฉัน ( * สะอื้น ... * ) และจะรับรองสิ่งนี้แทน
efotinis

18
นอกจากนี้ยังทำให้''.splitlines() == []ไม่ได้เช่นเดียวกับ[''] ''.split('\n')
rightfold

198

เหมือนที่คนอื่นพูดว่า:

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

นี่เป็นเหมือนข้างต้น แต่ฟังก์ชั่นของโมดูลสตริงจะถูกคัดค้านและควรหลีกเลี่ยง:

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

อีกทางหนึ่งถ้าคุณต้องการให้แต่ละบรรทัดรวมลำดับการหยุดพัก (CR, LF, CRLF) ให้ใช้splitlinesเมธอดที่มีTrueอาร์กิวเมนต์:

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

12
สิ่งนี้จะทำงานกับระบบที่ใช้ '\ n' เป็นตัวยุติบรรทัด
Jeremy Cantrell

20
@Jeremy: ตัวอักษรสตริงที่ยกมาสามเท่ามักจะใช้ '\ n' EOL โดยไม่คำนึงถึงแพลตฟอร์ม ดังนั้นไฟล์ที่อ่านในโหมดข้อความ
efotinis

16
inputString.split(os.linesep)จะใช้จุดสิ้นสุดบรรทัดเฉพาะแพลตฟอร์ม
James

10
มันแปลกที่คำตอบนี้ได้รับการโหวตขึ้นอย่างมาก การเข้ารหัสฮาร์ด '\ n' เป็นความคิดที่ไม่ดี แต่แม้ว่าคุณจะใช้ os.linesep แทนที่จะเป็นคุณก็จะมีปัญหากับ windows line ลงท้ายบน Linux และในทางกลับกันเป็นต้นนอกจากนี้ยังเป็นการส่งเสริมการแยกแบบแบ่งย่อยด้วยอาร์กิวเมนต์ True ซึ่งเป็น น่าจะเป็นวิธีที่ใช้กันโดยทั่วไปน้อยกว่าในการใช้ ...
lpapp

4
การรวมกันของวิธีการที่ไม่ดีที่สุดวิธีการเลิกใช้และรูปแบบที่ซ้ำซ้อนของวิธีการที่ดีที่สุด
jwg

50

str.splitlines()ใช้

splitlines()split("\n")จับขึ้นบรรทัดใหม่อย่างถูกต้องซึ่งแตกต่างจาก

นอกจากนี้ยังมีข้อได้เปรียบที่กล่าวถึงโดย @efotinis ของทางเลือกรวมถึงอักขระขึ้นบรรทัดใหม่ในผลการแยกเมื่อถูกเรียกด้วยTrueอาร์กิวเมนต์


คำอธิบายโดยละเอียดเกี่ยวกับสาเหตุที่คุณไม่ควรใช้split("\n"):

\nใน Python หมายถึงตัวแบ่งบรรทัด Unix (รหัสทศนิยมสิบ ASCII 10) เป็นอิสระจากแพลตฟอร์มที่คุณเรียกใช้ อย่างไรก็ตามตัวแทน LINEBREAK คือขึ้นอยู่กับแพลตฟอร์ม บน Windows, \nเป็นตัวละครทั้งสองCRและLF(ASCII รหัสทศนิยม 13 และ 10 AKA \rและ\n) ในขณะที่บน Unix ทันสมัยใด ๆ (รวมทั้ง OS X) LFก็เป็นตัวเดียว

printตัวอย่างเช่นทำงานได้อย่างถูกต้องแม้ว่าคุณจะมีสตริงที่ลงท้ายด้วยบรรทัดที่ไม่ตรงกับแพลตฟอร์มของคุณ:

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

อย่างไรก็ตามการแยก "\ n" อย่างชัดเจนจะทำให้เกิดพฤติกรรมที่ขึ้นกับแพลตฟอร์ม:

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

แม้ว่าคุณจะใช้os.linesepมันจะแยกตามตัวคั่นบรรทัดใหม่บนแพลตฟอร์มของคุณและจะล้มเหลวหากคุณกำลังประมวลผลข้อความที่สร้างขึ้นในแพลตฟอร์มอื่น ๆ หรือเปล่า\n:

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

splitlines แก้ปัญหาเหล่านี้ทั้งหมด:

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

การอ่านไฟล์ในโหมดข้อความบางส่วนช่วยลดปัญหาการขึ้นบรรทัดใหม่ขณะที่มันแปลง Python เป็นการ\nขึ้นบรรทัดใหม่ของแพลตฟอร์ม อย่างไรก็ตามโหมดข้อความมีอยู่บน Windows เท่านั้น บนระบบ Unix ไฟล์ทั้งหมดจะถูกเปิดในโหมดไบนารีดังนั้นการใช้split('\n')ในระบบ UNIX ที่มีไฟล์ Windows จะทำให้เกิดพฤติกรรมที่ไม่พึงประสงค์ นอกจากนี้การประมวลผลสตริงด้วยการขึ้นบรรทัดใหม่อาจแตกต่างจากแหล่งอื่น ๆ เช่นจากซ็อกเก็ต


การเปรียบเทียบนั้นไม่ยุติธรรมเพราะคุณสามารถใช้ split (os.linesep) ได้เช่นกันเพื่อหลีกเลี่ยงบิตเฉพาะแพลตฟอร์ม
lpapp

6
@lpapp note ที่splitlinesจะแยกในตอนท้ายบรรทัดใด ๆ split(os.linesep)จะล้มเหลวเมื่ออ่านไฟล์ windows ในระบบยูนิกซ์เช่น
goncalopp

1
อีกเหตุผลสำหรับการใช้ splitlines ในกรณีของฉันขอบคุณ ฉันให้ +1 ฉันเองจะรวมข้อมูลในความคิดเห็นลงในคำตอบของคุณ
lpapp

20

อาจ overkill ในกรณีนี้ แต่ตัวเลือกอื่นที่เกี่ยวข้องกับการใช้StringIOเพื่อสร้างวัตถุเหมือนไฟล์

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

ใช่นี่เป็นวิธีที่เข้าใจได้ง่ายที่สุดของ Python-ic
ครัวซองต์ Paramagnetic

4
ข้อได้เปรียบให้วิธีนี้เมื่อเทียบกับการstr.splitเป็นที่ไม่จำเป็นต้องจัดสรรหน่วยความจำใด ๆ (อ่านสตริงในสถานที่) ข้อเสียคือมันช้าลงมากถ้าคุณใช้StringIO (ประมาณ 50x) ถ้าคุณใช้cStringIOมันจะเร็วขึ้นประมาณ 2x
goncalopp

เร็วกว่าอะไร 2x
Irina Rapoport

1
@IrinaRapoport, cStringIO เร็วขึ้นกว่า StringIO 2x
iruvar

1

โพสต์ต้นฉบับขอรหัสที่พิมพ์บางแถว (หากเป็นจริงสำหรับเงื่อนไขบางอย่าง) บวกกับแถวต่อไปนี้ การใช้งานของฉันจะเป็นเช่นนี้:

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

ฉันต้องการความคิดเห็นที่มีการจัดรูปแบบข้อความรหัสที่เหมาะสมเพราะฉันคิดว่า @ 1_CR คำตอบต้องการการกระแทกมากกว่าและฉันต้องการที่จะเพิ่มคำตอบของเขา อย่างไรก็ตามเขานำฉันไปสู่เทคนิคดังต่อไปนี้ มันจะใช้ cStringIO ถ้ามี (แต่หมายเหตุ: cStringIO และ StringIO จะไม่เหมือนกันเพราะคุณไม่สามารถ subclass cStringIO ... มันเป็นในตัว ... แต่สำหรับการดำเนินการขั้นพื้นฐานไวยากรณ์จะเหมือนกันดังนั้นคุณสามารถทำสิ่งนี้ได้ ):

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

for line in StringIO.StringIO(variable_with_multiline_string):
    pass
print line.strip()
โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.