【问题标题】:Only first character of unicode strings getting written to csv只有 unicode 字符串的第一个字符被写入 csv
【发布时间】:2013-06-30 19:31:47
【问题描述】:

我的问题的简而言之,我的脚本无法将完整的 unicode 字符串(从数据库中检索)写入 csv,而是仅将每个字符串的 第一个字符 写入文件。例如:

U,1423.0,831,1,139

输出应该在哪里:

University of Washington Students,1423.0,831,1,139

一些背景知识:我正在使用 pyodbc 连接到 MSSQL 数据库。我为 unicode 设置了我的 odbc 配置文件,并按如下方式连接到数据库:

p.connect("DSN=myserver;UID=username;PWD=password;DATABASE=mydb;CHARSET=utf-8")

我可以获取数据没有问题,但是当我尝试将查询结果保存到 csv 文件时出现问题。我尝试使用 csv.writer,官方文档中的 UnicodeWriter 解决方案,以及最近在 github 上找到的 unicodecsv 模块。每种方法产生相同的结果。

奇怪的是我可以在 python 控制台中打印字符串没有问题。但是,如果我将相同的字符串写入 csv,就会出现问题。请参阅下面的测试代码和结果:

突出问题的代码:

print "'Raw' string from database:"
print "\tencoding:\t" + whatisthis(report.data[1][0])
print "\tprint string:\t" + report.data[1][0]
print "\tstring len:\t" + str(len(report.data[1][0]))

f = StringIO()
w = unicodecsv.writer(f, encoding='utf-8')
w.writerows(report.data)
f.seek(0)
r = unicodecsv.reader(f)
row = r.next()
row = r.next()

print "Write/Read from csv file:"
print "\tencoding:\t" + whatisthis(row[0])
print "\tprint string:\t" + row[0]
print "\tstring len:\t" + str(len(row[0]))

测试输出:

'Raw' string from database:
    encoding: unicode string
    print string: University of Washington Students
    string len: 66
Write/Read from csv file:
    encoding: unicode string
    print string: U
    string len: 1

此问题的原因可能是什么?我该如何解决?谢谢!

编辑:whatisthis 函数只是检查字符串格式,取自this post

def whatisthis(s):
    if isinstance(s, str):
        print "ordinary string"
    elif isinstance(s, unicode):
        print "unicode string"
    else:
        print "not a string"

【问题讨论】:

  • 你为什么要执行 r.next() 两次?你不是在第一种情况下打印第二行,在第二种情况下打印第三行吗?
  • 那只是因为第一行是字段名,是我后来添加的。我只是做了两次 r.next() 来突出问题。
  • 我在尝试使用 csvsql 将 csv 数据加载到 mssql 时遇到了类似的问题。所有文本字段都作为单个字符加载。知道它可能是什么吗?文件的编码应该是什么? (驱动是 Ubuntu 上的 freetds)

标签: python csv unicode pyodbc


【解决方案1】:
import StringIO as sio
import unicodecsv as ucsv

class Report(object):
    def __init__(self, data):
        self.data = data

report = Report( 
  [
     ["University of Washington Students", 1, 2, 3],
     ["UCLA", 5, 6, 7]
  ]
)



print report.data
print report.data[0][0]

print "*" * 20

f = sio.StringIO()
writer = ucsv.writer(f, encoding='utf-8')
writer.writerows(report.data)

print f.getvalue()
print "-" * 20

f.seek(0)

reader = ucsv.reader(f)
row = reader.next()

print row
print row[0]



--output:--
[['University of Washington Students', 1, 2, 3], ['UCLA', 5, 6, 7]]
University of Washington Students
********************
University of Washington Students,1,2,3
UCLA,5,6,7

--------------------
[u'University of Washington Students', u'1', u'2', u'3']
University of Washington Students

谁知道你的 whatisthis() 函数在搞什么鬼。

【讨论】:

  • 如果我自己在代码中创建列表,如上所述,那么没有问题。问题是由于我从数据库中提取的 unicode 数据。请参阅我的解释 whatisthis 函数的编辑。
  • 为什么还要在代码中包含 whatis() 函数?它是如何相关的?你得到什么输出:打印类型(report.data)?
  • 你得到了什么:打印report.data?
  • 这是我打印 report.data 时的输出:[(u'U\x00n\x00i\x00v\x00e\x00r\x00s\x00i\x00t\x00y\x00 \x00o\x00f\x00 \x00W\x00a\x00s\x00h\x00i\x00n\x00g\x00t\x00o\x00n\x00 \x00S\x00t\x00u\x00d\x00e\x00n\x00t\x00s\x00', u'2\x000\x001\ x003\x00-\x000\x006\x00-\x002\x009\x00', 1423.0, 831, 1, 139)]
  • 您的数据库数据未以 UTF-8 编码。对于 report.data 中的每个字符,有两个字节:U\x00, n\x00, etc. 每个字符的第二个字节是 \x00,这是一个空字节,因为您的字符都适合第一个字节。换句话说,您的数据库编码每个字符使用固定的两个字节。 UTF-8 编码是不同的。查看 mssql 文档,看起来编码是 ucs2,每个字符固定两个字节。 python没有ucs2编解码器来解码这样的字符串,但是你可以试试“utf_16_le”。
猜你喜欢
  • 2018-08-19
  • 2021-12-07
  • 2023-03-17
  • 1970-01-01
  • 1970-01-01
  • 2019-09-04
  • 2017-04-06
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多