ข้ามส่วนหัวเมื่อแก้ไขไฟล์ csv โดยใช้ Python


209

ฉันใช้โค้ดด้านล่างเพื่อแก้ไข csv โดยใช้ Python ฟังก์ชั่นที่เรียกว่าในรูปแบบรหัสส่วนบนของรหัส

ปัญหา: ฉันต้องการรหัสอ้างอิงด้านล่างเพื่อเริ่มแก้ไข csv จากแถวที่ 2 ฉันต้องการให้ยกเว้นแถวที่ 1 ซึ่งมีส่วนหัว ตอนนี้มันใช้ฟังก์ชั่นในแถวที่ 1 เท่านั้นและแถวส่วนหัวของฉันก็เปลี่ยนไป

in_file = open("tmob_notcleaned.csv", "rb")
reader = csv.reader(in_file)
out_file = open("tmob_cleaned.csv", "wb")
writer = csv.writer(out_file)
row = 1
for row in reader:
    row[13] = handle_color(row[10])[1].replace(" - ","").strip()
    row[10] = handle_color(row[10])[0].replace("-","").replace("(","").replace(")","").strip()
    row[14] = handle_gb(row[10])[1].replace("-","").replace(" ","").replace("GB","").strip()
    row[10] = handle_gb(row[10])[0].strip()
    row[9] = handle_oem(row[10])[1].replace("Blackberry","RIM").replace("TMobile","T-Mobile").strip()
    row[15] = handle_addon(row[10])[1].strip()
    row[10] = handle_addon(row[10])[0].replace(" by","").replace("FREE","").strip()
    writer.writerow(row)
in_file.close()    
out_file.close()

ฉันพยายามที่จะแก้ปัญหานี้โดยการเริ่มต้นrowตัวแปรให้1แต่มันไม่ทำงาน

โปรดช่วยฉันในการแก้ปัญหานี้


คำตอบ:


370

readerตัวแปรของคุณนั้นสามารถทำซ้ำได้โดยการวนลูปมากกว่าที่คุณดึงแถว

หากต้องการให้ข้ามหนึ่งรายการก่อนวงของคุณเพียงแค่เรียกnext(reader, None)และละเว้นค่าส่งคืน

คุณสามารถทำให้รหัสของคุณง่ายขึ้นเล็กน้อย ใช้ไฟล์ที่เปิดเป็นตัวจัดการบริบทเพื่อให้ปิดโดยอัตโนมัติ:

with open("tmob_notcleaned.csv", "rb") as infile, open("tmob_cleaned.csv", "wb") as outfile:
   reader = csv.reader(infile)
   next(reader, None)  # skip the headers
   writer = csv.writer(outfile)
   for row in reader:
       # process each row
       writer.writerow(row)

# no need to close, the files are closed automatically when you get to this point.

หากคุณต้องการเขียนส่วนหัวไปยังไฟล์เอาต์พุตที่ไม่ได้ประมวลผลนั่นก็ง่ายเช่นกันให้ส่งผ่านผลลัพธ์ของnext()ไปที่writer.writerow():

headers = next(reader, None)  # returns the headers or `None` if the input is empty
if headers:
    writer.writerow(headers)

22
อีกทางเลือกหนึ่งคือใช้for row in islice(reader, 1, None)- แม้ว่าจะชัดเจนน้อยกว่าnextสำหรับงาน "ข้ามหนึ่งบรรทัด" ที่ง่ายที่สุดสำหรับการข้ามแถวส่วนหัวหลายแถว (หรือรับเฉพาะบางส่วน ฯลฯ ... ) มันค่อนข้างมีประโยชน์
Jon Clements

ฉันจะพิจารณาใช้try: writer.write(next(reader))... except StopIteration: # handle empty reader
Jon Clements

@ JonClements: บางที ทำงานได้ดีพอโดยไม่ต้องสอนเกี่ยวกับtry:/except: /
Martijn Pieters

1
@JonClements: ความได้เปรียบในnextการทำซ้ำอย่างชัดเจนคือมันเป็น "ฟรี"; isliceจะห่อreaderค่าใช้จ่ายตลอดไป (จำนวนที่ยอมรับน้อยมาก) ค่าใช้จ่ายในการทำซ้ำแต่ละครั้ง consumeสูตรจากitertoolsสามารถนำมาใช้เพื่อข้ามค่าจำนวนมากได้อย่างรวดเร็วโดยไม่ต้องเพิ่มการตัดการใช้งานที่ตามมาในกรณีที่isliceจะมีstartแต่ไม่มีendดังนั้นค่าใช้จ่ายที่ไม่ได้ดึงดูดคุณอะไร
ShadowRanger

120

อีกวิธีในการแก้ปัญหานี้คือการใช้คลาส DictReader ซึ่ง "ข้าม" แถวส่วนหัวและใช้เพื่ออนุญาตการสร้างดัชนีที่มีชื่อ

รับ "foo.csv" ดังนี้:

FirstColumn,SecondColumn
asdf,1234
qwer,5678

ใช้ DictReader เช่นนี้:

import csv
with open('foo.csv') as f:
    reader = csv.DictReader(f, delimiter=',')
    for row in reader:
        print(row['FirstColumn'])  # Access by column header instead of column number
        print(row['SecondColumn'])

21
ฉันรู้สึกเหมือนนี้เป็นคำตอบที่แท้จริงเป็นคำถามที่น่าจะเป็นตัวอย่างของปัญหา XY
MariusSiuram

3
DictReader เป็นวิธีที่จะไปแน่นอน
Javier Arias

4
เป็นสิ่งสำคัญที่จะต้องทราบว่าจะใช้งานได้เฉพาะเมื่อคุณละเว้นพารามิเตอร์ชื่อเขตข้อมูลเมื่อสร้าง DictReader ตามเอกสาร: If the fieldnames parameter is omitted, the values in the first row of the file f will be used as the fieldnames.ดูdocs.python.org/2/library/csv.html
BuvinJ

7

การทำrow=1จะไม่เปลี่ยนแปลงอะไรเลยเพราะคุณเพียงแค่เขียนทับสิ่งนั้นด้วยผลลัพธ์ของลูป

คุณต้องการnext(reader)ข้ามไปหนึ่งแถว


ฉันลองเปลี่ยนเป็นfor row in next(reader):แต่มันทำให้ฉันมีIndexError: string index out of rangeข้อผิดพลาด

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