2012-07-03 38 views
18

Chương trình của tôi cần đọc các tệp csv có thể có 1,2 hoặc 3 cột và cần phải sửa đổi hành vi của các cột đó cho phù hợp. Có cách nào đơn giản để kiểm tra số cột mà không "tiêu thụ" một hàng trước khi trình vòng lặp chạy không? Các mã sau đây là thanh lịch nhất mà tôi có thể quản lý, nhưng tôi muốn để chạy kiểm tra trước khi cho vòng lặp bắt đầu:Tìm số cột trong tệp csv

import csv 
f = 'testfile.csv' 
d = '\t' 

reader = csv.reader(f,delimiter=d) 
for row in reader: 
    if reader.line_num == 1: fields = len(row) 
    if len(row) != fields: 
     raise CSVError("Number of fields should be %s: %s" % (fields,str(row))) 
    if fields == 1: 
     pass 
    elif fields == 2: 
     pass 
    elif fields == 3: 
     pass 
    else: 
     raise CSVError("Too many columns in input file.") 

Edit: tôi nên đã đưa thêm thông tin về dữ liệu của tôi. Nếu chỉ có một trường, nó phải có tên trong ký hiệu khoa học. Nếu có hai trường, trường đầu tiên phải chứa tên và mã thứ hai là mã liên kết. Nếu có ba trường, trường bổ sung chứa một cờ chỉ định liệu tên đó có hợp lệ hay không. Do đó nếu bất kỳ hàng nào có 1, 2 hoặc 3 cột, tất cả đều phải giống nhau.

+0

tốt hơn sử dụng 'fields' thay vì 'rows' . –

+0

@MarcodeWit cảm ơn, tất nhiên nó phải là 'trường'! Tôi cũng đồng ý với quan điểm của bạn rằng không phải tất cả các hàng nhất thiết phải có cùng số trường. Trong trường hợp này, tôi đã quyết định sẽ tăng một ngoại lệ nếu gặp phải một hàng như vậy. – rudivonstaden

Trả lời

18

Bạn có thể sử dụng itertools.tee

itertools.tee (iterable [, n = 2])
Return n lặp độc lập từ một iterable duy nhất.

ví dụ:

reader1, reader2 = itertools.tee(csv.reader(f, delimiter=d)) 
columns = len(next(reader1)) 
del reader1 
for row in reader2: 
    ... 

Lưu ý rằng điều quan trọng là để xóa các tài liệu tham khảo để reader1 khi bạn kết thúc với nó - nếu không tee sẽ phải lưu trữ tất cả các hàng trong bộ nhớ trong trường hợp bạn đã bao giờ gọi next(reader1) lại

4

gì xảy ra nếu người dùng cung cấp cho bạn tệp CSV có ít cột hơn? Các giá trị mặc định có được sử dụng thay thế không?

Nếu vậy, tại sao không mở rộng hàng có giá trị null thay thế?

reader = csv.reader(f,delimiter=d) 
for row in reader: 
    row += [None] * (3 - len(row)) 
    try: 
     foo, bar, baz = row 
    except ValueError: 
     # Too many values to unpack: too many columns in the CSV 
     raise CSVError("Too many columns in input file.") 

Thanh và baz sẽ ít nhất là None và trình xử lý ngoại lệ sẽ xử lý bất kỳ hàng nào dài hơn 3 mục.

+0

Vấn đề với phương pháp này là mỗi hàng phải có cùng một dữ liệu trong mỗi trường, nhưng dữ liệu khó xác thực. – rudivonstaden

+0

Tôi không thấy cách tiếp cận của tôi đặt thêm bất kỳ ràng buộc nhất quán nào hơn là chỉ kiểm tra độ dài của hàng đầu tiên. Bên cạnh đó, bạn không cho chúng tôi biết nhiều về dữ liệu của bạn; do đó câu trả lời của tôi bắt đầu bằng một câu hỏi. –

+0

bạn nói đúng, tôi đã chỉnh sửa câu hỏi của mình để bao gồm thêm về dữ liệu và cũng bao gồm kiểm tra tính nhất quán cho mỗi hàng. – rudivonstaden

7

Điều này dường như làm việc tốt:

import csv 

datafilename = 'testfile.csv' 
d = '\t' 
f=open(datafilename,'r') 

reader=csv.reader(f,delimiter=d) 
ncol=len(next(reader)) # Read first line and count columns 
f.seek(0)    # go back to beginning of file 
for row in reader: 
    pass #dostuff 
-1

tôi sẽ xây dựng lại nó như sau (nếu các tập tin không phải là quá lớn):

import csv 
f = 'testfile.csv' 
d = '\t' 

reader = list(csv.reader(f,delimiter=d)) 
fields = len(reader[0]) 
for row in reader: 
    if fields == 1: 
     pass 
    elif fields == 2: 
     pass 
    elif fields == 3: 
     pass 
    else: 
     raise CSVError("Too many columns in input file.") 
+0

@Martijn Pieters: Đó là lý do tại sao tôi bắt đầu với cảnh báo về việc kích hoạt tệp. Hàm 'list' sao chép mọi thứ từ trình lặp, do đó chỉ có các tệp csv nhỏ phù hợp. –

+0

Vì vậy, bạn thực sự làm vậy. –

+0

Tôi sẽ không xây dựng lại mã nếu tệp quá lớn. –

Các vấn đề liên quan