ฉันมีสตริงตัวอักษรหลายบรรทัดที่ฉันต้องการดำเนินการในแต่ละบรรทัดเช่น:
inputString = """Line 1
Line 2
Line 3"""
ฉันต้องการทำสิ่งต่อไปนี้:
for line in inputString:
doStuff()
ฉันมีสตริงตัวอักษรหลายบรรทัดที่ฉันต้องการดำเนินการในแต่ละบรรทัดเช่น:
inputString = """Line 1
Line 2
Line 3"""
ฉันต้องการทำสิ่งต่อไปนี้:
for line in inputString:
doStuff()
คำตอบ:
inputString.splitlines()
จะให้รายการกับแต่ละรายการsplitlines()
วิธีการออกแบบมาเพื่อแยกแต่ละบรรทัดเป็นองค์ประกอบรายการ
''.splitlines() == []
ไม่ได้เช่นเดียวกับ['']
''.split('\n')
เหมือนที่คนอื่นพูดว่า:
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']
inputString.split(os.linesep)
จะใช้จุดสิ้นสุดบรรทัดเฉพาะแพลตฟอร์ม
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 จะทำให้เกิดพฤติกรรมที่ไม่พึงประสงค์ นอกจากนี้การประมวลผลสตริงด้วยการขึ้นบรรทัดใหม่อาจแตกต่างจากแหล่งอื่น ๆ เช่นจากซ็อกเก็ต
splitlines
จะแยกในตอนท้ายบรรทัดใด ๆ split(os.linesep)
จะล้มเหลวเมื่ออ่านไฟล์ windows ในระบบยูนิกซ์เช่น
อาจ overkill ในกรณีนี้ แต่ตัวเลือกอื่นที่เกี่ยวข้องกับการใช้StringIO
เพื่อสร้างวัตถุเหมือนไฟล์
for line in StringIO.StringIO(inputString):
doStuff()
str.split
เป็นที่ไม่จำเป็นต้องจัดสรรหน่วยความจำใด ๆ (อ่านสตริงในสถานที่) ข้อเสียคือมันช้าลงมากถ้าคุณใช้StringIO
(ประมาณ 50x) ถ้าคุณใช้cStringIO
มันจะเร็วขึ้นประมาณ 2x
โพสต์ต้นฉบับขอรหัสที่พิมพ์บางแถว (หากเป็นจริงสำหรับเงื่อนไขบางอย่าง) บวกกับแถวต่อไปนี้ การใช้งานของฉันจะเป็นเช่นนี้:
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])
ฉันต้องการความคิดเห็นที่มีการจัดรูปแบบข้อความรหัสที่เหมาะสมเพราะฉันคิดว่า @ 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()