从dictreader转换非ASCII字符为ASCII

0 投票
2 回答
2323 浏览
提问于 2025-04-18 18:48
  File "F:...files.py", line 9, in files
    for row in f:
  File "C:\Python27\lib\csv.py", line 104, in next
    row = self.reader.next()
  File "C:\Python27\lib\codecs.py", line 684, in next
    return self.reader.next()
  File "C:\Python27\lib\codecs.py", line 615, in next
    line = self.readline()
  File "C:\Python27\lib\codecs.py", line 530, in readline
    data = self.read(readsize, firstline=True)
  File "C:\Python27\lib\codecs.py", line 477, in read
    newchars, decodedbytes = self.decode(data, self.errors)
UnicodeDecodeError: 'utf8' codec can't decode byte 0xfc in position 0: invalid start byte

关于Python和unicode/字符串的问题有很多。不过,之前的回答对我都没用。

首先,我用DictReader打开一个文件,然后把每一行放进一个数组里。接着,把字典里的值转换成unicode。

第一步是获取数据。

f = csv.DictReader(open(filename,"r")
data = []
for row in f:
    data.append(row)

第二步是从字典中获取字符串值,并替换掉重音符(这个是我从其他帖子上找到的)。

s = data[i].get('Name')
strip_accents(s)

def strip_accents(s):
    try: s = unicode(s)
    except: s = s.encode('utf-8')
    s = unicodedata.normalize('NFKD', s).encode('ascii','ignore')
    return s

我使用try和except是因为有些字符串有重音符,有些则没有。我搞不明白的是,unicode(s)在没有重音符的type str上能正常工作,但如果type str有重音符,就会出错。

UnicodeDecodeError: 'ascii' codec can't decode byte 0xfc in position 11: ordinal not in range(128)

我见过关于这个的帖子,但那些答案都不管用。当我用type(s)检查时,它显示是<type 'str'>。所以我尝试把文件当作unicode来读取。

f = csv.DictReader(codecs.open(filename,"r",encoding='utf-8'))

但一读取就出现了这个错误:

data = []
for row in f:
    data.append(row)

这个错误是因为dictreader处理unicode的方式造成的吗?我该怎么解决这个问题呢?


更多测试。正如@univerio指出的,导致失败的一个原因是ISO-8859-1。

我把打开文件的语句修改为:

f = csv.DictReader(codecs.open(filename,"r",encoding="cp1252"))

结果出现了一个稍微不同的错误:

  File "F:...files.py", line 9, in files
    for row in f:
  File "C:\Python27\lib\csv.py", line 104, in next
    row = self.reader.next()
UnicodeEncodeError: 'ascii' codec can't encode character u'\xfc' in position 11: ordinal not in range(128)

使用基本的打开语句,并修改strip_accents(),像这样:

try: s = unicode(s)
except: s = s.decode("iso-8859-1").encode('utf8')
print type(s)
s = unicodedata.normalize('NFKD', s).encode('ascii','ignore')
return str(s)

打印出来的类型仍然是str,并且出错。

s = unicodedata.normalize('NFKD', s).encode('ascii','ignore')
TypeError: must be unicode, not str

根据这个Python: 从ISO-8859-1/latin1转换到UTF-8的帖子,修改为:

s = unicode(s.decode("iso-8859-1").encode('utf8'))

结果又出现了不同的错误:

except: s = unicode(s.decode("iso-8859-1").encode('utf8'))
UnicodeDecodeError: 'ascii' codec can't decode byte 0xc3 in position 11: ordinal not in range(128)

2 个回答

0

参考链接在这里: Unicode编码错误: 'ascii' 编码无法在位置0编码字符u'\xef': 序号不在范围(128)内,这是@Duncan的回答。

print repr(ch)

示例:

string = 'Ka\u011f KO\u011e52 \u0131 \u0130\u00f6\u00d6 David \u00fc K\u00dc\u015f\u015e \u00e7 \u00c7'

print (repr(string))

它输出:

'Kağ KOĞ52 ı İöÖ David ü KÜşŞ ç Ç'
1

我觉得这样做应该可以:

def strip_accents(s):
    s = s.decode("cp1252")  # decode from cp1252 encoding instead of the implicit ascii encoding used by unicode()
    s = unicodedata.normalize('NFKD', s).encode('ascii','ignore')
    return s

之所以用正确的编码打开文件没有成功,是因为 DictReader 似乎不能正确处理 Unicode 字符串。

撰写回答