2013-05-01 42 views
40

Tôi muốn nhập hai loại tệp CSV, một số sử dụng ";" cho dấu phân tách và các dấu khác sử dụng ",". Cho đến nay tôi đã được chuyển đổi giữa hai dòng tiếp theo:Tôi có thể nhập tệp CSV và tự động suy ra dấu phân tách không?

reader=csv.reader(f,delimiter=';') 

hoặc

reader=csv.reader(f,delimiter=',') 

Có thể không xác định dấu phân cách và để cho việc kiểm tra chương trình cho delimiter phải không?

Các giải pháp dưới đây (Máy xay sinh tố và sharth) có vẻ hoạt động tốt cho các tệp được phân tách bằng dấu phẩy (được tạo bằng Libroffice) nhưng không cho các tệp được phân cách bằng dấu chấm phẩy (được tạo bằng MS Office). Dưới đây là những dòng đầu tiên của một tập tin dấu chấm phẩy:

ReleveAnnee;ReleveMois;NoOrdre;TitreRMC;AdopCSRegleVote;AdopCSAbs;AdoptCSContre;NoCELEX;ProposAnnee;ProposChrono;ProposOrigine;NoUniqueAnnee;NoUniqueType;NoUniqueChrono;PropoSplittee;Suite2LecturePE;Council PATH;Notes 
1999;1;1;1999/83/EC: Council Decision of 18 January 1999 authorising the Kingdom of Denmark to apply or to continue to apply reductions in, or exemptions from, excise duties on certain mineral oils used for specific purposes, in accordance with the procedure provided for in Article 8(4) of Directive 92/81/EEC;U;;;31999D0083;1998;577;COM;NULL;CS;NULL;;;;Propos* are missing on Celex document 
1999;1;2;1999/81/EC: Council Decision of 18 January 1999 authorising the Kingdom of Spain to apply a measure derogating from Articles 2 and 28a(1) of the Sixth Directive (77/388/EEC) on the harmonisation of the laws of the Member States relating to turnover taxes;U;;;31999D0081;1998;184;COM;NULL;CS;NULL;;;;Propos* are missing on Celex document 
+0

Xin chào một cuộc thảo luận chung hơn (không phải trong python) cũng nằm trong https://stackoverflow.com/questions/2789695/how-to-programmatically-guess-whether-a-csv-file-is-comma-or- semicolon-delimited – Lorenzo

Trả lời

6

Để giải quyết sự cố, tôi đã tạo một hàm đọc dòng đầu tiên của tệp (tiêu đề) và phát hiện dấu phân cách.

def detectDelimiter(csvFile): 
    with open(csvFile, 'r') as myCsvfile: 
     header=myCsvfile.readline() 
     if header.find(";")!=-1: 
      return ";" 
     if header.find(",")!=-1: 
      return "," 
    #default delimiter (MS Office export) 
    return ";" 
+5

Chức năng của bạn sẽ không hoạt động nếu dấu phân cách là một phần của một giá trị, ngay cả khi nó được định hình hoặc trích dẫn. Ví dụ, một dòng như "" Hi Peter; "," Bạn thế nào? "," Tạm biệt John! ",' Sẽ trả về '; 'làm dấu phân cách, điều đó sai. – tashuhka

42

Module csv dường như khuyên bạn sử dụng các csv sniffer cho vấn đề này.

Chúng đưa ra ví dụ sau, mà tôi đã thích nghi cho trường hợp của bạn.

with open('example.csv', 'rb') as csvfile: # python 3: 'r',newline="" 
    dialect = csv.Sniffer().sniff(csvfile.read(1024), delimiters=";,") 
    csvfile.seek(0) 
    reader = csv.reader(csvfile, dialect) 
    # ... process CSV file contents here ... 

Hãy thử nó ra.

[9:13am][[email protected] /tmp] cat example 
#!/usr/bin/env python 
import csv 

def parse(filename): 
    with open(filename, 'rb') as csvfile: 
     dialect = csv.Sniffer().sniff(csvfile.read(), delimiters=';,') 
     csvfile.seek(0) 
     reader = csv.reader(csvfile, dialect) 

     for line in reader: 
      print line 

def main(): 
    print 'Comma Version:' 
    parse('comma_separated.csv') 

    print 
    print 'Semicolon Version:' 
    parse('semicolon_separated.csv') 

    print 
    print 'An example from the question (kingdom.csv)' 
    parse('kingdom.csv') 

if __name__ == '__main__': 
    main() 

Và đầu vào mẫu của chúng tôi

[9:13am][[email protected] /tmp] cat comma_separated.csv 
test,box,foo 
round,the,bend 

[9:13am][[email protected] /tmp] cat semicolon_separated.csv 
round;the;bend 
who;are;you 

[9:22am][[email protected] /tmp] cat kingdom.csv 
ReleveAnnee;ReleveMois;NoOrdre;TitreRMC;AdopCSRegleVote;AdopCSAbs;AdoptCSContre;NoCELEX;ProposAnnee;ProposChrono;ProposOrigine;NoUniqueAnnee;NoUniqueType;NoUniqueChrono;PropoSplittee;Suite2LecturePE;Council PATH;Notes 
1999;1;1;1999/83/EC: Council Decision of 18 January 1999 authorising the Kingdom of Denmark to apply or to continue to apply reductions in, or exemptions from, excise duties on certain mineral oils used for specific purposes, in accordance with the procedure provided for in Article 8(4) of Directive 92/81/EEC;U;;;31999D0083;1998;577;COM;NULL;CS;NULL;;;;Propos* are missing on Celex document 
1999;1;2;1999/81/EC: Council Decision of 18 January 1999 authorising the Kingdom of Spain to apply a measure derogating from Articles 2 and 28a(1) of the Sixth Directive (77/388/EEC) on the harmonisation of the laws of the Member States relating to turnover taxes;U;;;31999D0081;1998;184;COM;NULL;CS;NULL;;;;Propos* are missing on Celex document 

Và nếu chúng ta thực hiện các chương trình ví dụ:

[9:14am][[email protected] /tmp] ./example 
Comma Version: 
['test', 'box', 'foo'] 
['round', 'the', 'bend'] 

Semicolon Version: 
['round', 'the', 'bend'] 
['who', 'are', 'you'] 

An example from the question (kingdom.csv) 
['ReleveAnnee', 'ReleveMois', 'NoOrdre', 'TitreRMC', 'AdopCSRegleVote', 'AdopCSAbs', 'AdoptCSContre', 'NoCELEX', 'ProposAnnee', 'ProposChrono', 'ProposOrigine', 'NoUniqueAnnee', 'NoUniqueType', 'NoUniqueChrono', 'PropoSplittee', 'Suite2LecturePE', 'Council PATH', 'Notes'] 
['1999', '1', '1', '1999/83/EC: Council Decision of 18 January 1999 authorising the Kingdom of Denmark to apply or to continue to apply reductions in, or exemptions from, excise duties on certain mineral oils used for specific purposes, in accordance with the procedure provided for in Article 8(4) of Directive 92/81/EEC', 'U', '', '', '31999D0083', '1998', '577', 'COM', 'NULL', 'CS', 'NULL', '', '', '', 'Propos* are missing on Celex document'] 
['1999', '1', '2', '1999/81/EC: Council Decision of 18 January 1999 authorising the Kingdom of Spain to apply a measure derogating from Articles 2 and 28a(1) of the Sixth Directive (77/388/EEC) on the harmonisation of the laws of the Member States relating to turnover taxes', 'U', '', '', '31999D0081', '1998', '184', 'COM', 'NULL', 'CS', 'NULL', '', '', '', 'Propos* are missing on Celex document'] 

Nó cũng có thể là đáng chú ý những gì phiên bản của python Tôi đang sử dụng.

[9:20am][[email protected] /tmp] python -V 
Python 2.7.2 
+0

Điều đó làm việc cho tệp được phân tách bằng dấu phẩy nhưng tệp được phân cách bằng dấu chấm phẩy không thể đọc được chính xác (Không thể xác định dấu phân tách). Xem bản chỉnh sửa của tôi ở trên ... – rom

+0

Nó có vẻ phù hợp với tôi. Tôi sẽ mở rộng câu trả lời. –

+0

Tôi đã bao gồm một ví dụ có dấu phẩy được phân tách, dấu chấm phẩy được tách riêng và tệp mẫu mà bạn đề xuất trong câu hỏi. –

2

Tôi không nghĩ rằng có thể là một giải pháp hoàn hảo để chung này (một trong những lý do tôi có thể sử dụng , như một dấu phân cách là một số lĩnh vực dữ liệu của tôi cần để có thể bao gồm ; ...). Một cách đơn giản để quyết định có thể đơn giản là đọc dòng đầu tiên (hoặc nhiều hơn), đếm số lượng ,; ký tự chứa (có thể bỏ qua những dấu ngoặc kép bên trong, nếu bất kỳ điều gì tạo ra các tệp .csv báo giá mục nhập chính xác và nhất quán), và đoán thường xuyên hơn của hai là dấu phân cách đúng.

7

Cho dự án thỏa thuận với cả hai (dấu phẩy) và | (Dọc thanh) được phân định file CSV, mà được hình thành tốt, tôi đã cố gắng như sau (như được đưa ra tại https://docs.python.org/2/library/csv.html#csv.Sniffer):

dialect = csv.Sniffer().sniff(csvfile.read(1024), delimiters=',|') 

Tuy nhiên, trên một | Tập -delimited, "không thể xác định dấu phân cách" ngoại lệ được trả lại . Nó có vẻ hợp lý để suy đoán rằng các heuristic sniff có thể làm việc tốt nhất nếu mỗi dòng có cùng một số delimiters (không kể bất cứ điều gì có thể được kèm theo trong dấu ngoặc kép).Vì vậy, thay vì đọc 1024 byte đầu tiên của tệp, tôi đã thử đọc hai dòng đầu tiên trong toàn bộ:

temp_lines = csvfile.readline() + '\n' + csvfile.readline() 
dialect = csv.Sniffer().sniff(temp_lines, delimiters=',|') 

Cho đến nay, điều này có hiệu quả đối với tôi.

+2

Điều này rất hữu ích đối với tôi! Tôi đã gặp sự cố với dữ liệu trong đó một trong các giá trị "được chốt" là các số có dấu phẩy trong chúng, do đó, nó vẫn không thành công. Điều này hạn chế nó để 2 dòng đầu tiên thực sự giúp đỡ. – mauve

+0

Tuyệt vời, đã làm việc cho tôi với các tệp "csv" riêng của tôi. Cảm ơn :) – EisenHeim

6

Và nếu bạn đang sử dụng DictReader bạn có thể làm điều đó:

#!/usr/bin/env python 
import csv 

def parse(filename): 
    with open(filename, 'rb') as csvfile: 
     dialect = csv.Sniffer().sniff(csvfile.read(), delimiters=';,') 
     csvfile.seek(0) 
     reader = csv.DictReader(csvfile, dialect=dialect) 

     for line in reader: 
      print(line['ReleveAnnee']) 

tôi đã sử dụng điều này với Python 3.5 và nó làm việc theo cách này.

+1

Tôi đã sử dụng nó trong python 2.7 – alvaro562003