2012-07-07 11 views
12

मैं None और पाइथन डेटा संरचना और सीएसवी प्रतिनिधित्व के बीच पाइथन के csv मॉड्यूल का उपयोग करके खाली स्ट्रिंग्स को अलग करना चाहता हूं।सीएसवी रीडर व्यवहार कोई और खाली स्ट्रिंग

input : [['NULL/None value', None], ['empty string', '']] 
output: [['NULL/None value', ''], ['empty string', '']] 

बेशक, मैं data और data2 के साथ खेल सकते चीजों के साथ None और रिक्त स्ट्रिंग भेद करने के लिए:

import csv, cStringIO 

data = [['NULL/None value',None], 
     ['empty string','']] 

f = cStringIO.StringIO() 
csv.writer(f).writerows(data) 

f = cStringIO.StringIO(f.getvalue()) 
data2 = [e for e in csv.reader(f)] 

print "input : ", data 
print "output: ", data2 

मैं निम्नलिखित उत्पादन प्राप्त करें:

मेरे मुद्दा यह है कि जब मैं चलाने है जैसे:

data = [d if d!=None else 'None' for d in data] 
data2 = [d if d!='None' else None for d in data2] 

लेकिन वह डब्ल्यू csv मॉड्यूल (सी में लागू त्वरित deserialization/serialization, विशेष रूप से जब आप बड़ी सूचियों से निपट रहे हैं) के मेरे हित को आंशिक रूप से हराया जाएगा।

वहाँ एक csv.Dialect या पैरामीटर csv.writer करने और csv.reader है कि उन्हें इस यूज-केस में '' और None के बीच अंतर करने के लिए सक्षम होगा है?

यदि नहीं, तो csv.writer पर इस पैच को आगे बढ़ाने के लिए पैच को लागू करने में कोई दिलचस्पी होगी? (संभावित रूप से Dialect.None_translate_to पैरामीटर पिछली संगतता सुनिश्चित करने के लिए '' पर डिफ़ॉल्ट पैरामीटर)

उत्तर

7

The documentation पता चलता है कि क्या आप चाहते हैं संभव नहीं है:

यह संभव के रूप में आसान मॉड्यूल जो डीबी API के कार्यान्वयन के साथ इंटरफेस करने के लिए, मूल्य नहीं है खाली स्ट्रिंग के रूप में लिखा है।

यह सुझाव यह सब बोलियों के लिए सच है और सीएसवी मॉड्यूल का एक आंतरिक सीमा है, writer वर्ग के लिए दस्तावेज में है।

मैं इसे बदलने के लिए (सीएसवी मॉड्यूल की कई अन्य सीमाओं के साथ) को बदलने का समर्थन करता हूं, लेकिन हो सकता है कि लोग इस तरह के काम को एक अलग पुस्तकालय में ऑफ़लोड करना चाहते हैं, और सीएसवी मॉड्यूल को सरल रखें (या कम से कम जितना सरल है)।

यदि आपको अधिक शक्तिशाली फ़ाइल-पढ़ने की क्षमताओं की आवश्यकता है, तो हो सकता है कि आप सीएसवी रीडिंग फ़ंक्शंस को numpy, scipy, और पांडा में देखना चाहें, जैसा कि मुझे याद है कि मुझे और विकल्प हैं।

+0

यप ने पुष्टि की: मॉड्यूल/_csv.c में csv_writerow को देख रहे हैं (यदि (फ़ील्ड == Py_None) ...)। '' और किसी के बीच अंतर करने का कोई तरीका नहीं है। वास्तव में एक शर्म की बात है, डायलेक्ट अमूर्तता के बाद आप थोड़ा अधिक लचीलापन की उम्मीद कर सकते थे। आप सीएसवी मॉड्यूल की अन्य सीमाओं का जिक्र करते हैं, क्या आप विस्तार से ध्यान देंगे (यदि अन्य मुद्दे हैं तो मुझे वास्तव में अन्य सीएसवी-रीडिंग लेखन को देखना शुरू करना चाहिए)? – user1509316

+0

एक सीमा जो मुझे कभी-कभी परेशान होती है वह यह है कि delimiters एक ही चरित्र होना चाहिए। तो आप एक फ़ाइल को पार्स नहीं कर सकते हैं जहां कॉलम अलग-अलग हैं, कहें, दो टैब। किसी भी चीज़ की तरह आप पार नहीं हुआ, यह काम करने के लिए काफी आसान है, लेकिन अभी भी परेशान है। – BrenBarn

+0

मॉड्यूल के भीतर एक और हार्ड कोडित ascii सीमा है। –

1

मुझे नहीं लगता कि यह केवल एक बोलीभाषा के साथ आप करना चाहते हैं, लेकिन आप अपना स्वयं का csv.reader/लिखना सबक्लास लिख सकते हैं। दूसरी ओर, मुझे अभी भी लगता है कि इस उपयोग के मामले में अधिक है। यहां तक ​​कि अगर तुम सिर्फ None की तुलना में अधिक पकड़ने के लिए चाहते हैं, तो आप शायद सिर्फ str() हैं:

>>> data = [['NULL/None value',None],['empty string','']] 
>>> i = cStringIO.StringIO() 
>>> csv.writer(i).writerows(map(str,row) for row in data) 
>>> print i.getvalue() 
NULL/None value,None 
empty string, 
+0

वास्तव में, आप 'csv.reader' और' csv.writer' को उपclass नहीं कर सकते हैं। – martineau

1

तुम दोनों उपभोक्ता और धारावाहिक डेटा के निर्माता पर नियंत्रण है के रूप में, एक प्रारूप है कि गौरव का समर्थन करता है कि प्रयोग करने पर विचार।

उदाहरण:

>>> import json 
>>> json.dumps(['foo', '', None, 666]) 
'["foo", "", null, 666]' 
>>> 
9

आप कर सकते थे कम से कम आंशिक ओर कदम क्या csv मॉड्यूल एक सिंगलटन None तरह वर्ग/मूल्य के अपने स्वयं के संस्करण बनाने के द्वारा करता है:

class NONE(object): 
    def __repr__(self): # method csv.writer class uses to write values 
     return 'NONE' # unique string value to represent None 
    def __len__(self): # method called to determine length and truthiness 
     return 0  # (optional) 

NONE = NONE() # singleton instance of the class 

import csv 
import cStringIO 

data = [['None value', None], ['NONE value', NONE], ['empty string', '']] 
f = cStringIO.StringIO() 
csv.writer(f).writerows(data) 
f = cStringIO.StringIO(f.getvalue()) 
print " input:", data 
print "output:", [e for e in csv.reader(f)] 

परिणाम:

input: [['None value', None], ['NONE value', NONE], ['empty string', '']] 
output: [['None value', ''], ['NONE value', 'NONE'], ['empty string', '']] 

NONE का उपयोग करना None के बजाय आपके और इसके वास्तविक खाली-स्ट्रिंग डेटा मानों के बीच अंतर करने में सक्षम होने के लिए पर्याप्त जानकारी सुरक्षित रखेगी।

और भी बेहतर विकल्प ...
आप अपेक्षाकृत हल्के csv.reader और csv.writer "प्रॉक्सी" वर्गों — आवश्यक की एक जोड़ी को लागू करने के लिए एक ही दृष्टिकोण का उपयोग कर सकता है के बाद से आप वास्तव में उपवर्ग नहीं कर सकते में निर्मित csv वर्ग है जो सी — में बहुत अधिक ओवरहेड पेश किए बिना लिखा गया है (क्योंकि अधिकांश प्रसंस्करण अभी भी अंतर्निहित अंतर्निर्मित द्वारा किया जाएगा)। इससे पूरी तरह से पारदर्शी हो जाता है क्योंकि यह सब प्रॉक्सी के भीतर encapsulated है।

import csv 

class csvProxyBase(object): _NONE = '<None>' # unique value representing None 

class csvWriter(csvProxyBase): 
    def __init__(self, csvfile, *args, **kwrags): 
     self.writer = csv.writer(csvfile, *args, **kwrags) 
    def writerow(self, row): 
     self.writer.writerow([self._NONE if val is None else val for val in row]) 
    def writerows(self, rows): 
     map(self.writerow, rows) 

class csvReader(csvProxyBase): 
    def __init__(self, csvfile, *args, **kwrags): 
     self.reader = csv.reader(csvfile, *args, **kwrags) 
    def __iter__(self): 
     return self 
    def next(self): 
     return [None if val == self._NONE else val for val in self.reader.next()] 

if __name__ == '__main__': 
    import cStringIO as StringIO 
    data = [['None value', None], ['empty string', '']] 
    f = StringIO.StringIO() 
    csvWriter(f).writerows(data) 
    f = StringIO.StringIO(f.getvalue()) 
    print " input:", data 
    print "output:", [e for e in csvReader(f)] 

परिणाम:

input: [['None value', None], ['empty string', '']] 
output: [['None value', None], ['empty string', '']] 
+0

पहले समाधान की एक भिन्नता ने मेरे लिए लिखने की समस्या हल की। एक __repr__ के साथ एक वर्ग (int) बनाया गया जो एक खाली स्ट्रिंग देता है। किसी के साथ सभी कोई भी मूल्य नहीं बदला गया (मुझे अपना डेटा प्रारूपित करना था, इसलिए कोई अतिरिक्त काम नहीं था)। फिर QUOTE_NONNUMERIC के साथ सीएसवी लेखक बनाएं। यह थोड़ा हैकी है, लेकिन इसका मतलब है कि आउटपुट फ़ाइल में आप जानते हैं कि एक उद्धृत फ़ील्ड हमेशा एक स्ट्रिंग है, और एक निर्विवाद खाली क्षेत्र हमेशा कोई नहीं होता है। – trelltron

+0

@ टॉम: मुझे यकीन नहीं है कि "किसी के साथ सभी कोई भी मूल्य नहीं बदला गया" क्योंकि आपने 'एनओएन' को 'int' subclass' परिभाषित किया है-ऐसा लगता है कि आपको एक पूर्णांक मूल्य प्रदान करने की आवश्यकता होगी 'NONE' के _instances_ बनाने के लिए। क्या आपने सिंगलटन बनाते समय ऐसा किया था? यानी 'नहीं = कोई नहीं (0)'। – martineau

+0

@ टॉम: कभी नहीं। मुझे अब एहसास है कि आपके 'NONE' उपclass' 0' के मान पर डिफ़ॉल्ट होने के 'int' वर्ग व्यवहार का उत्तराधिकारी होगा यदि निर्माण समय पर कोई मूल्य प्रदान नहीं किया जाता है। यानी 'int() 'का पूर्णांक मान डिफ़ॉल्ट रूप से शून्य है। – martineau

0

के रूप में अन्य लोगों ने बताया है तुम सच में csv.Dialect या csv.writer और/या csv.reader के मानकों के माध्यम से ऐसा नहीं कर सकते। हालांकि जैसा कि मैंने एक टिप्पणी में कहा था, आप इसे प्रभावी ढंग से द्वारा कार्यान्वित करते हैं जो बाद वाले दो को उप-वर्गीकृत करते हैं (आप स्पष्ट रूप से ऐसा नहीं कर सकते क्योंकि वे अंतर्निहित हैं)। क्या "उपवर्गों" लेखन पर क्या बस None मूल्यों अवरोधन है और उन्हें एक अद्वितीय स्ट्रिंग में बदल सकते हैं और प्रक्रिया जब उन्हें वापस पढ़ने रिवर्स यहाँ एक पूरी तरह से काम किया बाहर उदाहरण है:।

import csv, cStringIO 
NULL = '<NULL>' # something unlikely to ever appear as a regular value in your csv files 

class MyCsvWriter(object): 
    def __init__(self, *args, **kwrds): 
     self.csv_writer = csv.writer(*args, **kwrds) 

    def __getattr__(self, name): 
     return getattr(self.csv_writer, name) 

    def writerow(self, row): 
     self.csv_writer.writerow([item if item is not None else NULL 
             for item in row]) 
    def writerows(self, rows): 
     for row in rows: 
      self.writerow(row) 

class MyCsvReader(object): 
    def __init__(self, *args, **kwrds): 
     self.csv_reader = csv.reader(*args, **kwrds) 

    def __getattr__(self, name): 
     return getattr(self.csv_reader, name) 

    def __iter__(self): 
     rows = iter(self.csv_reader) 
     for row in rows: 
      yield [item if item != NULL else None for item in row] 

data = [['NULL/None value', None], 
     ['empty string', '']] 

f = cStringIO.StringIO() 
MyCsvWriter(f).writerows(data) # instead of csv.writer(f).writerows(data) 

f = cStringIO.StringIO(f.getvalue()) 
data2 = [e for e in MyCsvReader(f)] # instead of [e for e in csv.reader(f)] 

print "input : ", data 
print "ouput : ", data2 

आउटपुट:

input : [['NULL/None value', None], ['empty string', '']] 
ouput : [['NULL/None value', None], ['empty string', '']] 

यह एक टैड वर्बोज़ है और शायद & सीएसवी फ़ाइल को थोड़ा पढ़ने के लिए धीमा कर देता है (क्योंकि वे सी/सी ++ में लिखे गए हैं) लेकिन इससे थोड़ा अंतर हो सकता है क्योंकि प्रक्रिया की संभावना कम-स्तर I/O बाध्य है ।

संबंधित मुद्दे