TATECHATLAS
◎ हिन्दी
प्रोग्रामिंग

पायथन में विश्वसनीय CSV पार्सिंग: BOM, डायलेक्ट और नई पंक्तियों का प्रबंधन

पायथन के csv मॉड्यूल का उपयोग करके डिलीमीटर का स्वचालित रूप से पता लगाने, यूनिकोड बाइट ऑर्डर मार्क (BOM) को utf-8-sig के साथ संभालने और Sniffer क्लास और सही फ़ाइल ओपनिंग पैरामीटर्स के उपयोग से प्लेटफ़ॉर्म-विशिष्ट नई पंक्ति के मुद्दों का प्रबंधन करने का गाइड।

इस पृष्ठ पर

वैकल्पिक BOM वाली UTF-8 CSV के लिए encoding='utf-8-sig' और newline='' उपयोग करें। फ़ाइल का विभाजक ज्ञात हो तो उसे स्पष्ट रूप से दें। अज्ञात प्रारूप में Sniffer.sniff डिकोड किए हुए टेक्स्ट से प्रारूप का अनुमान लगाता है; वह हेडर की मौजूदगी नहीं पहचानता। DictReader से पहले कॉलम नाम जाँचें और csv.Error संभालें।

CSV डायलेक्ट और फॉर्मेट की समझ

CSV (कॉमा से अलग किए गए मान) फॉर्मेट के लिए एकल, सार्वभौमिक मानक नहीं है। जबकि RFC 4180 एक दिशा-निर्देश प्रदान करता है, बहुत से एप्लिकेशन, विशेष रूप से माइक्रोसॉफ्ट एक्सेल, डिलीमीटर, कोटिंग अक्षर और लाइन एंडिंग में सूक्ष्म अंतर लागू करते हैं। इन अंतरों के कारण हाथ से स्ट्रिंग स्प्लिटिंग अविश्वसनीय हो जाती है, क्योंकि एक ही फ़ाइल में सेमीकॉलन के बजाय कॉमा का उपयोग हो सकता है या जटिल कोटिंग नियम शामिल हो सकते हैं।

पायथन के csv मॉड्यूल ने 'डायलेक्ट' की अवधारणा के माध्यम से इन अंतरों को अब्स्ट्रैक्ट किया है। एक डायलेक्ट एक ऐसे पैरामीटरों का संग्रह है - जैसे डिलीमीटर, कोटिंग अक्षर और लाइनटर्मिनेटर - जो एक विशिष्ट एप्लिकेशन द्वारा डेटा के फॉर्मेट को परिभाषित करता है। प्रत्येक नए फ़ाइल स्रोत के लिए कस्टम पार्सिंग लॉजिक लिखे बिना, आप मॉड्यूल का उपयोग करके इन अंतरों को स्वचालित रूप से संभाल सकते हैं।

स्निफर के साथ स्वचालित फॉर्मेट डिटेक्शन

Sniffer.sniff टेक्स्ट स्ट्रिंग लेता है, कच्चे बाइट नहीं। 1024 अक्षरों का नमूना एक विकल्प है, विश्वसनीय न्यूनतम या गारंटी नहीं। नमूना पढ़ने के बाद फ़ाइल की स्थिति शुरू में लौटाएँ। Sniffer.has_header अलग और त्रुटिपूर्ण हो सकने वाला अनुमान है; ज्ञात निर्यात विनिर्देश अनुमान से बेहतर हैं।

बाइट ऑर्डर मार्क (BOM) का प्रबंधन

बहुत से विंडोज-आधारित एप्लिकेशन UTF-8 फ़ाइलों के शुरुआत में एक बाइट ऑर्डर मार्क (BOM) जोड़ते हैं ताकि एन्कोडिंग की पहचान की जा सके। यदि आप इस तरह की फ़ाइल को मानक 'utf-8' कोडेक के साथ खोलते हैं, तो BOM (बाइट अनुक्रम 0xef, 0xbb, 0xbf) को वास्तविक डेटा के रूप में लिया जाएगा, जिससे पहले कॉलम नाम में अदृश्य अक्षरों के कारण खराब हो जाते हैं।

इस समस्या को हल करने के लिए, open() फ़ंक्शन में 'utf-8-sig' एन्कोडिंग का उपयोग करें। यह कोडेक विशेष रूप से UTF-8 BOM की पहचान करने और डीकोडिंग प्रक्रिया के दौरान इसे छोड़ने के लिए डिज़ाइन किया गया है, जिससे आपका पहला हेडर नाम साफ और उपयोगी रहता है।

CSV के लिए फ़ाइल ओपनिंग का कॉन्फ़िगरेशन

csv मॉड्यूल का उपयोग करते समय एक सामान्य गलती यह है कि newline पैरामीटर को निर्दिष्ट न करना। पायथन के दस्तावेज़ीकरण के अनुसार, जब किसी फ़ाइल को csv मॉड्यूल के लिए खोलते हैं, तो आपको हमेशा newline='' का उपयोग करना चाहिए।

यदि आप इसे छोड़ देते हैं, तो पायथन I/O लेयर अपने नए लाइन ट्रांसलेशन कर सकता है, जिससे अप्रत्याशित व्यवहार हो सकता है, जैसे अतिरिक्त खाली पंक्तियां या आंतरिक लाइन ब्रेक वाले कोटेड फ़ील्ड का गलत प्रबंधन। newline='' सेट करने से csv मॉड्यूल के आंतरिक पार्सर को पूर्ण नियंत्रण लाइन अंत के लिए दे दिया जाता है।

csv.reader के साथ सूचियों के रूप में डेटा पढ़ना

csv.reader फ़ंक्शन एक इटरेटर लौटाता है जो प्रत्येक पंक्ति को स्ट्रिंग की सूची के रूप में देता है। जब आपको केवल डेटा की स्थिति (उदाहरण के लिए, तीसरा कॉलम) की आवश्यकता होती है और विशिष्ट नामों के साथ मानों को मैप करने की आवश्यकता नहीं होती है, तो यह आदर्श होता है। एक पता लगाए गए डायलेक्ट के साथ जोड़े जाने पर, रीडर सभी भारी काम को विभाजित और अनकोट करने के लिए देखता है।

import csv
from pathlib import Path

# Illustrative UTF-8 input with BOM, semicolons and a quoted newline.
Path('example.csv').write_text(
    '\ufeffID;Name\n1;"Ada; Lovelace"\n2;"Grace\nHopper"\n',
    encoding='utf-8', newline=''
)
with open('example.csv', newline='', encoding='utf-8-sig') as f:
    sample = f.read(1024)  # Characters, not bytes.
    f.seek(0)
    try:
        dialect = csv.Sniffer().sniff(sample, delimiters=',;\t')
    except csv.Error as error:
        raise ValueError('Cannot determine CSV dialect; specify it explicitly') from error
    for row in csv.reader(f, dialect=dialect):
        print(row)
# Expected illustrative output:
# ['ID', 'Name']
# ['1', 'Ada; Lovelace']
# ['2', 'Grace\nHopper']

DictReader के साथ पंक्तियों को शब्दकोशों में मैप करना

fieldnames न देने पर DictReader पहली पंक्ति को कुंजियाँ मानता है, चाहे Sniffer उपयोग हुआ हो या नहीं। अगला उदाहरण पिछले उदाहरण में बनाए ID और Name हेडर पर निर्भर है। हेडर न हो तो fieldnames स्पष्ट दें या csv.reader उपयोग करें। डेटा संसाधित करने से पहले अनपेक्षित कॉलम अस्वीकार करें।

सही हेडर हर पंक्ति में समान फ़ील्ड संख्या की गारंटी नहीं देता। DictReader सामान्यतः गायब मानों को None से भरता है और अतिरिक्त मानों को None कुंजी के अंतर्गत रखता है। दोहराए गए कॉलम नाम किसी डिक्शनरी मान को बदल सकते हैं। डेटा को सत्यापित मानने से पहले हेडर की विशिष्टता और पंक्ति संरचना जाँचें।

import csv

# Uses example.csv created above; its delimiter and header are known.
with open('example.csv', newline='', encoding='utf-8-sig') as f:
    reader = csv.DictReader(f, delimiter=';')
    if reader.fieldnames != ['ID', 'Name']:
        raise ValueError('Unexpected CSV header')
    for row in reader:
        print(row['ID'], repr(row['Name']))
# Expected illustrative output:
# 1 'Ada; Lovelace'
# 2 'Grace\nHopper' 

एन्कोडिंग और त्रुटि प्रबंधन का प्रबंधन

विविध डेटा स्रोतों के साथ काम करते समय, आपको ऐसे अक्षरों का सामना करना पड़ सकता है जो अपेक्षित एन्कोडिंग में फिट नहीं होते हैं। open() फ़ंक्शन में 'errors' तर्क की अनुमति है। 'strict' (डिफ़ॉल्ट) का उपयोग करने पर यदि कोई अमान्य बाइट मिलता है, तो यह UnicodeDecodeError उठाता है, जो डेटा वैधता के लिए उपयोगी है। यदि आप समस्याग्रस्त अक्षरों को छोड़ना चाहते हैं, तो आप 'ignore' या 'replace' का उपयोग कर सकते हैं।

हमेशा सुनिश्चित करें कि एन्कोडिंग स्रोत के साथ मेल खाती है। जबकि 'utf-8-sig' BOM को संभालता है, यदि फ़ाइल वास्तव में 'latin-1' में एन्कोडेड है, तो आपको उसे स्पष्ट रूप से निर्दिष्ट करना होगा ताकि डिकोडिंग त्रुटियाँ न हों।

कस्टम डायलेक्ट के साथ उन्नत प्रारूपण

यदि आपको एक अत्यधिक अनौपचारिक फ़ाइल प्रारूप मिलता है जिसे स्निफर पहचान नहीं पाता है, तो आप csv.register_dialect() का उपयोग करके एक कस्टम डायलेक्ट परिभाषित कर सकते हैं। इससे आप डिलीमिटर, कोट चरित्र और अन्य पैरामीटर को कड़े रूप से कोड कर सकते हैं, जिसे आप अपने रीडर या राइटर ऑब्जेक्ट में नाम से संदर्भित कर सकते हैं। यह विशेष रूप से एक संगठन के भीतर बार-बार उपयोग होने वाले व्यावसायिक फ़ाइल प्रारूपों के लिए उपयोगी होता है।

क्या जाँचें

  • सुनिश्चित करें कि open() फ़ंक्शन कॉल में newline='' मौजूद है।
  • यदि फ़ाइल में BOM है, तो encoding='utf-8-sig' का उपयोग करना सुनिश्चित करें।
  • sniffing के बाद फ़ाइल को रीडर में पास करने से पहले f.seek(0) कॉल करना सुनिश्चित करें।
  • sniffing के लिए नमूना आकार ऐसा होना चाहिए कि डिलीमीटर को पकड़ा जा सके।

csv.Sniffer.sniff() विधि ह्यूरिस्टिक्स का उपयोग करती है और यदि नमूना बहुत छोटा है या डेटा बहुत अनियमित है, तो यह गलत सकारात्मक या नकारात्मक परिणाम दे सकती है। DictReader को एक वैध हेडर पंक्ति की आवश्यकता होती है ताकि कीज़ सही तरीके से मैप की जा सकें; यदि कोई हेडर नहीं है, तो यह पहली पंक्ति को कीज़ के रूप में उपयोग करेगा, जिससे डेटा की हानि या त्रुटियां हो सकती हैं।

स्रोत

  1. Python: csv ↗
  2. Python: encodings ↗
ऊपर जाएँ ↑