2012-02-07 15 views
8

मेरे पास एक यूटीएफ -16 सीएसवी फ़ाइल है जिसे मुझे पढ़ना है। पायथन सीएसवी मॉड्यूल यूटीएफ -16 का समर्थन नहीं करता है।पायथन यूटीएफ -16 सीएसवी रीडर

मैं अजगर 2.7.2 का उपयोग कर रहा हूं। सीएसवी फाइलों को मुझे पार्स करने की ज़रूरत है, जो कई जीबी डेटा में बड़े पैमाने पर चल रहे हैं। test.csv होने के साथ नीचे

print repr(open('test.csv', 'rb').read(100)) 

आउटपुट जॉन Machin प्रश्नों के लिए

जवाब सिर्फ एबीसी सामग्री के रूप में

'\xff\xfea\x00b\x00c\x00' 

मैं csv फ़ाइल संयुक्त राज्य अमेरिका में खिड़कियों मशीन पर बनाया गया लगता है। मैं मैक ओएसएक्स शेर का उपयोग कर रहा हूँ।

यदि मैं फिहाग और test.csv द्वारा प्रदान किए गए कोड का उपयोग करता हूं जिसमें एक रिकॉर्ड होता है।

नमूना test.csv सामग्री का उपयोग किया गया। नीचे प्रिंट रेपर है (खुला ('test.csv', 'rb')। पढ़ा (1000)) उत्पादन

'\xff\xfe1\x00,\x002\x00,\x00G\x00,\x00S\x00,\x00H\x00 \x00f\x00\xfc\x00r\x00 \x00e\x00 \x00\x96\x00 \x00m\x00 \x00\x85\x00,\x00,\x00I\x00\r\x00\n\x00' 

phihag द्वारा कोड ऊपर कोड

['1', '2', 'G', 'S', 'H f\xc3\xbcr e \xc2\x96 m \xc2\x85'] 
['', '', 'I'] 
की

import codecs 
import csv 
with open('test.csv','rb') as f: 
     sr = codecs.StreamRecoder(f,codecs.getencoder('utf-8'),codecs.getdecoder('utf-8'),codecs.getreader('utf-16'),codecs.getwriter('utf-16'))  
     for row in csv.reader(sr): 
     print row 

आउटपुट

उम्मीद उत्पादन

['1', '2', 'G', 'S', 'H f\xc3\xbcr e \xc2\x96 m \xc2\x85','','I'] 

उत्तर

28

momen पर है टी, सीएसवी मॉड्यूल यूटीएफ -16 का समर्थन नहीं करता है।

अजगर 3.x में, सीएसवी एक पाठ-मोड फ़ाइल की उम्मीद है और आप बस एक और एन्कोडिंग के लिए मजबूर करने open की एन्कोडिंग पैरामीटर का उपयोग कर सकते हैं:

# Python 3.x only 
import csv 
with open('utf16.csv', 'r', encoding='utf16') as csvf: 
    for line in csv.reader(csvf): 
     print(line) # do something with the line 

पायथन 2.x में, आप इनपुट पुनःकूटित कर सकते हैं :

# Python 2.x only 
import codecs 
import csv 

class Recoder(object): 
    def __init__(self, stream, decoder, encoder, eol='\r\n'): 
     self._stream = stream 
     self._decoder = decoder if isinstance(decoder, codecs.IncrementalDecoder) else codecs.getincrementaldecoder(decoder)() 
     self._encoder = encoder if isinstance(encoder, codecs.IncrementalEncoder) else codecs.getincrementalencoder(encoder)() 
     self._buf = '' 
     self._eol = eol 
     self._reachedEof = False 

    def read(self, size=None): 
     r = self._stream.read(size) 
     raw = self._decoder.decode(r, size is None) 
     return self._encoder.encode(raw) 

    def __iter__(self): 
     return self 

    def __next__(self): 
     if self._reachedEof: 
      raise StopIteration() 
     while True: 
      line,eol,rest = self._buf.partition(self._eol) 
      if eol == self._eol: 
       self._buf = rest 
       return self._encoder.encode(line + eol) 
      raw = self._stream.read(1024) 
      if raw == '': 
       self._decoder.decode(b'', True) 
       self._reachedEof = True 
       return self._encoder.encode(self._buf) 
      self._buf += self._decoder.decode(raw) 
    next = __next__ 

    def close(self): 
     return self._stream.close() 

with open('test.csv','rb') as f: 
    sr = Recoder(f, 'utf-16', 'utf-8') 

    for row in csv.reader(sr): 
     print (row) 

open और codecs.open एक बीओएम के साथ शुरू करने के लिए फ़ाइल की आवश्यकता है। यदि ऐसा नहीं होता (या आप पायथन 2.x पर हैं) तो आप अब भी स्मृति में परिवर्तित कर सकते हैं, इस तरह:

try: 
    from io import BytesIO 
except ImportError: # Python < 2.6 
    from StringIO import StringIO as BytesIO 
import csv 
with open('utf16.csv', 'rb') as binf: 
    c = binf.read().decode('utf-16').encode('utf-8') 
for line in csv.reader(BytesIO(c)): 
    print(line) # do something with the line 
+0

आपकी प्रतिक्रिया के लिए धन्यवाद @ एफहाग। स्मृति में फ़ाइल लोड किए बिना ऐसा करने का कोई तरीका है? मेरी सीएसवी फ़ाइल बहुत बड़ी है। – venky

+0

@venky एक हैक के साथ अपडेट किया गया है जो 2.x में काम करना चाहिए। – phihag

+0

मुझे कैसे पता चलेगा कि फ़ाइल बीओएम से शुरू हो रही है या नहीं[email protected] – venky

-1

वैसे ही जैसे codecs.open के साथ अपने फ़ाइल को खोलने में

import codecs, csv 

stream = codecs.open(<yourfile.csv>, encoding="utf-16") 
reader = csv.reader(stream) 

और यूनिकोड तारों के साथ अपने प्रोग्राम के माध्यम से काम करें, क्योंकि आप should do anyway if you are processing text

+0

: लाइन अपवाद फेंकती है यूनिकोडएनकोड त्रुटि: 'ascii' कोडेक स्थिति में आप \ xed 'चरित्र को एन्कोड नहीं कर सकता 77: क्रमशः श्रेणी में नहीं (128) – venky

+0

यह पायथन 3.x में ठीक काम करता है (हालांकि कोई सिर्फ 'codecs.open' के बजाय' ओपन 'लिख सकता है), लेकिन 2.x में विफल रहता है क्योंकि 'csv' स्ट्रीम से पढ़े गए यूनिकोड वर्णों को फिर से एन्कोड करने का प्रयास करता है। – phihag

3

मैं दृढ़ता से सुझाव दूंगा कि आप अपनी फ़ाइल को यूटीएफ -8 में रिकोड करें। बहुत संभावना है कि आपके पास बीएमपी के बाहर कोई यूनिकोड वर्ण नहीं है, आप इस तथ्य का लाभ उठा सकते हैं कि यूटीएफ -16 आपकी इनपुट फ़ाइल से फिक्स्ड-लम्बाई ब्लॉक को पढ़ने के लिए एक निश्चित-लंबाई एन्कोडिंग है, बिना स्ट्रैडलिंग ब्लॉक के बारे में चिंता किए बिना सीमाओं।

चरण 1: निर्धारित करें कि वास्तव में आपके पास कौन सी एन्कोडिंग है।एन्कोडिंग का

print repr(open('thefile.csv', 'rb').read(100))

चार संभव तरीके u'abc'

\xfe\xff\x00a\x00b\x00c -> utf_16 
\xff\xfea\x00b\x00c\x00 -> utf_16 
\x00a\x00b\x00c -> utf_16_be 
a\x00b\x00c\x00 -> utf_16_le 

आप इस चरण के साथ किसी भी परेशानी है, तो इसके बाद के संस्करण के परिणामों को शामिल करने के लिए अपने प्रश्न को संपादित: अपनी फ़ाइल के पहले कुछ बाइट्स की जांच print repr()

चरण 2: यहाँ एक 2.x पायथन recode-UTF-16 * है करने वाली UTF-8 स्क्रिप्ट:

import sys 
infname, outfname, enc = sys.argv[1:4] 
fi = open(infname, 'rb') 
fo = open(outfname, 'wb') 
BUFSIZ = 64 * 1024 * 1024 
first = True 
while 1: 
    buf = fi.read(BUFSIZ) 
    if not buf: break 
    if first and enc == 'utf_16': 
     bom = buf[:2] 
     buf = buf[2:] 
     enc = {'\xfe\xff': 'utf_16_be', '\xff\xfe': 'utf_16_le'}[bom] 
     # KeyError means file doesn't start with a valid BOM 
    first = False 
    fo.write(buf.decode(enc).encode('utf8')) 
fi.close() 
fo.close() 

अन्य मामलों:

आप कहते हैं कि आपकी फ़ाइलों को भी पूरी फ़ाइल, recode पढ़ सकते हैं और पुनर्लेखन के लिए बड़े हैं, फिर भी आप vi में खोल सकते हैं। कृपया समझाएँ।

< 85> रिकॉर्ड के अंत के रूप में माना जा रहा चिंता का एक मामला है। ऐसा लगता है कि 0x85 को एनईएल (सी 1 नियंत्रण कोड, NEWLINE) के रूप में पहचाना जा रहा है। एक मजबूत संभावना है कि डेटा मूल रूप से कुछ विरासत एकल-बाइट एन्कोडिंग में एन्कोड किया गया था, जहां 0x85 का अर्थ है लेकिन झूठी धारणा के तहत यूटीएफ -16 में ट्रांसकोड किया गया है कि मूल एन्कोडिंग आईएसओ -885 9 -1 उर्फ ​​लैटिन 1 था। फ़ाइल कहां से उत्पन्न हुई? एक आईबीएम मेनफ्रेम? विंडोज/यूनिक्स/क्लासिक मैक? क्या देश, लोकेल, भाषा? आप स्पष्ट रूप से सोचते हैं कि < 85> एक नई लाइन के लिए नहीं है; आपको क्या लगता है इसका मतलब है?

कृपया 1 ऑनलाइन नमूना उपलब्ध कराए गए आंकड़ों के आधार पर sjmachin at lexicon dot net

को अद्यतन एक कट नीचे फ़ाइल की एक प्रतिलिपि (कि < 85> सामान में से कुछ भी शामिल है) भेजने के लिए स्वतंत्र लग रहा है।

यह मेरे संदेह की पुष्टि करता है। this पढ़ें।

... the C1 control characters ... are rarely used directly, except on specific platforms such as OpenVMS. When they turn up in documents, Web pages, e-mail messages, etc., which are ostensibly in an ISO-8859-n encoding, their code positions generally refer instead to the characters at that position in a proprietary, system-specific encoding such as Windows-1252 or the Apple Macintosh ("MacRoman") character set that use the codes provided for representation of the C1 set with a single 8-bit byte to instead provide additional graphic characters

इस कोड:

s1 = '\xff\xfe1\x00,\x002\x00,\x00G\x00,\x00S\x00,\x00H\x00 \x00f\x00\xfc\x00r\x00 \x00e\x00 \x00\x96\x00 \x00m\x00 \x00\x85\x00,\x00,\x00I\x00\r\x00\n\x00' 
s2 = s1.decode('utf16') 
print 's2 repr:', repr(s2) 
from unicodedata import name 
from collections import Counter 
non_ascii = Counter(c for c in s2 if c >= u'\x80') 
print 'non_ascii:', non_ascii 
for c in non_ascii: 
    print "from: U+%04X %s" % (ord(c), name(c, "<no name>")) 
    c2 = c.encode('latin1').decode('cp1252') 
    print "to: U+%04X %s" % (ord(c2), name(c2, "<no name>")) 

s3 = u''.join(
    c.encode('latin1').decode('1252') if u'\x80' <= c < u'\xA0' else c 
    for c in s2 
    ) 
print 's3 repr:', repr(s3) 
print 's3:', s3 

निम्नलिखित का उत्पादन (अजगर 2.7.2 निष्क्रिय, विंडोज 7):

s2 repr: u'1,2,G,S,H f\xfcr e \x96 m \x85,,I\r\n' 
non_ascii: Counter({u'\x85': 1, u'\xfc': 1, u'\x96': 1}) 
from: U+0085 <no name> 
to: U+2026 HORIZONTAL ELLIPSIS 
from: U+00FC LATIN SMALL LETTER U WITH DIAERESIS 
to: U+00FC LATIN SMALL LETTER U WITH DIAERESIS 
from: U+0096 <no name> 
to: U+2013 EN DASH 
s3 repr: u'1,2,G,S,H f\xfcr e \u2013 m \u2026,,I\r\n' 
s3: 1,2,G,S,H für e – m …,,I 

जो तुम कर लगता है कि एक है यहाँ यह एक उद्धरण है \x96 की अधिक उचित व्याख्या:

एसपीए यानी संरक्षित क्षेत्र का प्रारंभ (ब्लॉक-ओरी द्वारा उपयोग किया गया लुप्तप्राय टर्मिनल।)
या
EN DASH
?

ऐसा लगता है कि बहुत अधिक डेटा नमूना का पूर्ण विश्लेषण जरूरी है। मदद करने के लिए खुश।

+0

अद्यतन प्रश्न अधिक जानकारी – venky

+0

@venky: उत्तर अपडेट किया गया। –

4

पायथन 2.x csv मॉड्यूल प्रलेखन example अन्य एन्कोडिंग को संभालने का तरीका दिखाता है।

+1

वास्तव में प्रलेखन क्या कहता है: "तो आप उन कार्यों या कक्षाओं को लिख सकते हैं जो आपके लिए एन्कोडिंग और डिकोडिंग को संभालते हैं जब तक आप यूटीएफ -16 जैसे एन्कोडिंग से बचें जो एनयूएल का उपयोग करते हैं।" –

+0

@ एंटनी ने क्या आपने अंतिम उदाहरण पढ़ा? यह सीएसवी मॉड्यूल को पास करने से पहले यूटीएफ -8 के रूप में किसी भी एन्कोडिंग में रिकोड करता है। –

+0

हां, समस्या को केवल कुछ पंक्तियों में संबोधित किया गया है जो @ फिहाग के उत्तर से कोड के समान ही हैं। मैं स्पष्ट रूप से उदाहरण उद्धृत करूंगा - पाठक के जीवन को आसान बनाने के लिए :) डाउनवोट हटा दिया गया। –

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