سؤال

أحاول ترجمة جدول بيانات Excel إلى CSV باستخدام وحدات Python XLRD و CSV، لكنني أشعر بالتعلق حول مشكلات الترميز. تنتج XLRD الإخراج من Excel في Unicode، ويتطلب وحدة CSV UTF-8.

أنا تصوير أن هذا لا علاقة له بوحدة XLRD: كل شيء يعمل على إخراج جيد إلى Stdout أو مخرجات أخرى لا تتطلب ترميز معين.

يتم تشفير ورقة العمل كما UTF-16-LE، وفقا ل book.encoding

النسخة المبسطة لما أفعله هو:

from xlrd import *
import csv
b = open_workbook('file.xls')
s = b.sheet_by_name('Export')
bc = open('file.csv','w')
bcw = csv.writer(bc,csv.excel,b.encoding)
for row in range(s.nrows):
    this_row = []
    for col in range(s.ncols):
        this_row.append(s.cell_value(row,col))
    bcw.writerow(this_row)

هذا ينتج الخطأ التالي، حوالي 740 سطر في:

UnicodeEncodeError: 'ascii' codec can't encode character u'\xed' in position 5: ordinal not in range(128)

يبدو أن القيمة هي الحصول على تعليقها هو "516-777316" - النص في ورقة Excel الأصلية هو "516-7773167" (مع 7 في النهاية)

سأكون أول من أعترف أن لدي سوى إحساس غامض بكيفية تشفير الشخصية، لذلك معظم ما جربته حتى الآن .encode و .decode على ال s.cell_value(row,col)

إذا كان شخص ما يمكن أن يقترح حلا، فستكون ممتنا له - حتى أفضل إذا كان بإمكانك تقديم تفسير لما لا يعمل ولماذا، حتى أتمكن من تصحيح هذه المشاكل نفسي في المستقبل.

شكرا مقدما!

تعديل:

شكرا على التعليقات حتى الآن.

عندما أنا المستخدم this_row.append(s.cell(row,col)) (egscell بدلا من s.cell_value) يكتب المستند بأكملها دون أخطاء.

الناتج غير مرغوب فيه بشكل خاص (text:u'516-7773167')، لكنه يتجنب الخطأ على الرغم من أن الشخصيات المخالفة لا تزال في الإخراج.

هذا يجعلني أعتقد أن التحدي قد يكون في XLRD بعد كل شيء.

أفكار؟

هل كانت مفيدة؟

المحلول

أتوقع cell_value قيمة الإرجاع هي سلسلة Unicode التي تعطيك مشاكل (يرجى طباعة type() لتأكيد ذلك)، في هذه الحالة يجب أن تكون قادرا على حلها عن طريق تغيير هذا السطر واحد:

this_row.append(s.cell_value(row,col))

ل:

this_row.append(s.cell_value(row,col).encode('utf8'))

إذا cell_value يتم إرجاع أنواع مختلفة متعددة، ثم تحتاج إلى الترميز إذا وفقط إذا كان بإرجاع سلسلة Unicode؛ لذلك كنت تنقسم هذا الخط إلى بعض الأسطر:

val = s.cell_value(row, col)
if isinstance(val, unicode):
    val = val.encode('utf8')
this_row.append(val)

نصائح أخرى

لقد طلبت التفسيرات، لكن بعض الظواهر لا يمكن تفسيرها دون مساعدتكم.

(أ) يتم ترميز السلاسل في ملفات XLS التي تم إنشاؤها بواسطة Excel 97 فصاعدا في Latin1 إذا أمكن ذلك بطريقة أخرى في UTF16LE. كل سلسلة تحمل تخبر العلم الذي تم استخدامه. في وقت سابق يتفوق سلاسل ترميز وفقا ل "Codepage" للمستخدم. على كل حال، XLRD تنتج كائنات يونيكود. وبعد يتم ترميز الملف ذو الاهتمام فقط عند إنشاء ملف XLS بواسطة برنامج الحزب الثالث الذي يغلي إما Codepage أو يكمن حوله. راجع قسم Unicode يصل الجزء الأمامي من مستندات XLRD.

(ب) ظاهرة غير مفسرة:

هذا الرمز:

bcw = csv.writer(bc,csv.excel,b.encoding)

يؤدي الخطأ التالي في Python 2.5 و 2.6 و 3.1: TypeError: expected at most 2 arguments, got 3 - هذا يدور حول ما أتوقعه منح المستندات على CSV.Writer؛ يتوقع وجود كائن Filelike متبوعا إما (1) لا شيء (2) لهجة أو (3) معاملات تنسيق واحد أو أكثر. لقد أعطيتها لهجة، ولا يوجد لدى CSV.Writer أي حجة ترميز، جدا splat. ما هو إصدار بيثون الذي تستخدمه؟ أم أنك لم نسخ / لصق البرنامج النصي الذي تدور بالفعل؟

(ج) الظواهر غير المبررة حول Traceback وما هي البيانات المخالفة الفعلية:

"the_script.py", line 40, in <module>
this_row.append(str(s.cell_value(row,col)))
UnicodeEncodeError: 'ascii' codec can't encode character u'\xed' in position 5: ordinal not in range(128) 

أولا، هناك شارع () في سطر التعليمات البرمجية الإساءة التي لم يكن في البرنامج النصي المبسط - هل لم نسخ / لصق البرنامج النصي الذي تدور بالفعل؟ في أي حال، يجب ألا تستخدم Str بشكل عام - فلن تحصل على الدقة الكاملة على عواماتك؛ فقط دع وحدة CSV تحويلها.

ثانيا، أنت تقول "" "" "" يبدو أن القيمة تتعلق هي "516-777316" - النص الموجود في ورقة Excel الأصلية هو "516-7773167" (مع 7 في النهاية) "" - - من الصعب تخيل كيف تضيع 7 من النهاية. كنت أستخدم شيئا مثل هذا لمعرفة بالضبط ما كانت البيانات المشكلة:

try:
    str_value = str(s.cell_value(row, col))
except:
    print "row=%d col=%d cell_value=%r" % (row, col, s.cell_value(row, col))
    raise

هذا٪ ص يحفظ عليك من الكتابة cell_value=%s ... repr(s.cell_value(row, col)) ... تنتج () تنتج تمثيلا لا لبس فيه لبياناتك. تعلمه. استخدامه.

كيف وصلت إلى "516-77316"؟

ثالثا، تكون رسالة الخطأ تشكو في الواقع من حرف Unicode U " XED" في Offset 5 (أي الشخصية السادسة). U + 00ed هو حرف صغير اللاتينية أنا مع حادة، ولا يوجد شيء مثل ذلك على الإطلاق في "516-7773167"

رابعا، يبدو موقع الخطأ مستهدفا متحركا - قلت في تعليق على أحد الحلول: "الخطأ موجود على bcw.writerow." هاه؟

(د) لماذا حصلت على رسالة الخطأ هذه (مع STR ()): str(a_unicode_object) لا تستخدم محاولات تحويل كائن Unicode إلى كائن Str وفي غياب أي معلومات ترميز ASCII، ولكن لديك بيانات غير ASCII، Slat جدا. لاحظ أن كائنك هو إنتاج ملف CSV مشفرة في UTF8، لكن البرنامج النصي المبسط لا يذكر UTF8 في أي مكان.

(ه) "" ... S.Cell (صف، العقيد)) (EGSCLEL بدلا من s.cell_value) الوثيقة بأكملها تكتب دون أخطاء. الناتج غير مرغوب فيه بشكل خاص (النص: U516-7773167 ")" "

هذا يحدث لأن كاتب CSV يدعو __str__ طريقة كائن الخلية الخاص بك، وهذا ينتج <type>:<repr(value)> والتي قد تكون مفيدة لتصحيح الأخطاء ولكن كما تقول ليست كبيرة في ملف CSV الخاص بك.

(و) حل أليكس مارتلي أمر رائع في أنه حصلت على الذهاب. ومع ذلك، يجب عليك قراءة القسم الموجود على فئة الخلية في مستندات XLRD: أنواع الخلية هي النص والرقم والمنطقية والتاريخ والخطأ والفارغة والفارغة. إذا كانت لديك تواريخ، فسوف ترغب في تنسيقها كتواريخ لا أرقام، لذلك لا يمكنك استخدام ISINSTANCE () (وقد لا ترغب في استدعاء الوظيفة النفقات العامة على أي حال) ... هذا هو ما Cell.ctype السمة و Sheet.cell_type() و Sheet.row_types() الأساليب هي ل.

(ز) UTF8 ليس Unicode. UTF16LE ليس Unicode. UTF16 ليس UNOCODE ... وفكرة أن الأوتار الفردية سوف تضيع 2 بايت كل منها على أموال UTF16 غير جاهزة جدا حتى يتفكر MS للتفكير :-)

(ح) قراءة أخرى (بصرف النظر عن مستندات XLRD):

http://www.joelonsoftware.com/articles/Unicode.html
http://www.amk.ca/python/howto/unicode

يبدو أنك حصلت على مشاكل 2.

هناك شيء مشدود في تلك الخلية - يجب تشفير "7" كما u'x37 "أعتقد، لأنه ضمن نطاق ASCII.

الأهم من ذلك، حقيقة أنك تحصل على رسالة خطأ تحدد ذلك ascii لا يمكن استخدام برنامج الترميز يشير إلى خطأ ما في ترميزك في Unicode - وهو يعتقد أنك تحاول تشفير قيمة 0xed لا يمكن تمثيلها في ASCII، لكنك قلت أنك تحاول تمثيلها في Unicode.

أنا لست ذكي بما فيه الكفاية للعمل. ما هو خط معين يسبب المشكلة - إذا قمت بتحرير سؤالك لتخبرني عن الخط الذي يسبب رسالة الخطأ التي قد أكون قادرا على المساعدة أكثر قليلا (أعتقد أنها أيضا this_row.append(s.cell_value(row,col)) أو bcw.writerow(this_row), ، ولكن من شأنه أن يقدرك تأكيد).

يبدو أن هناك احتمالين. واحد هو أنك لم تفتح ملف الإخراج بشكل صحيح:

"إذا كان CSVFILE كائن ملف، فيجب فتح علامة" B "على المنصات التي تحدث فرقا". في http://docs.python.org/library/csv.html#module-csv. )

إذا لم تكن هذه هي المشكلة، ثم خيار آخر لك هو استخدام Codecs.EncoDedFile (الملف أو الإدخال [أو الإخراج [أخطاء]]) كغلاف لإخراج .csv:

http://docs.python.org/library/codecs.html#module-codecs.

سيتيح لك ذلك الحصول على عامل تصفية كائن الملف من UTF16 الوارد إلى UTF8. في حين أن كل منهما "Unicode" من الناحية تقنيا، فإن الطريقة التي تشفص بها مختلفة تماما.

شيء من هذا القبيل:

rbc = open('file.csv','w')
bc = codecs.EncodedFile(rbc, "UTF16", "UTF8")
bcw = csv.writer(bc,csv.excel)

قد يحل المشكلة بالنسبة لك، على افتراض أنني فهمت المشكلة الصحيحة، وافتراض أن الخطأ يتم طرحه عند الكتابة إلى الملف.

مرخصة بموجب: CC-BY-SA مع الإسناد
لا تنتمي إلى StackOverflow
scroll top