Python: for-iteration through a utf-8 string -> 迭代器的数据 type/encoding 是什么?
Python: for-iteration through a utf-8 string -> what's the data type/encoding of the iterators?
我有一个utf-8编码的字符串(主要是中文+一些英文),想运行算一个字母。 (类似于英语单词计数)。
所以我用了
for letter in text: # text is a utf-8 encoded str
但我不确定 'letter' 我得到了什么。 'text' 在屏幕上打印和写入 csv 都很好。但是 'for letter in text' 中的 'letter' 在屏幕和 csv 文件中看起来都崩溃了。我认为这肯定是与编码相关的一些问题,但是在这里和那里添加 .encode('utf-8')
并不能解决问题并且 return 像
这样的错误
UnicodeDecodeError: 'ascii' codec can't decode byte 0x83 in position 0: ordinal not in range(128)
我的意思是下面的代码没有 return 错误但是字母看起来都崩溃了,当我添加 .encode('utf-8') 至
打印 letter.encode('utf-8')
或 wcwriter.writerows([[k.encode('utf-8'), v]])
# -*- coding: utf-8 -*-
...
with open(fname+'.csv', 'wb') as twfile:
twwriter = csv.writer(twfile)
twwriter.writerows([[u'Date/Time', u'Text', u'ID', u'Location', u'City', u'Province']])
for statuses in jres.get('statuses'): # jres is a json format response returned from a API call request
text = statuses.get('text').encode('utf-8')
if keyword in text:
td = statuses.get('created_at').encode('utf-8')
name = statuses.get('user').get('screen_name').encode('utf-8')
loc = statuses.get('user').get('location').encode('utf-8')
city = statuses.get('user').get('city').encode('utf-8')
province = statuses.get('user').get('province').encode('utf-8')
twwriter.writerows([[td, text, name, loc, city, province]])
keycount += 1
# this is the problematic part. I'm not sure exactly what data type or encoding I'm getting for 'letter' below
for letter in text:
if letter not in dismiss:
print letter # this will print a lot of crushed letters
if letter not in wordcount:
wordcount[letter] = 1
else:
wordcount[letter] += 1
with open(wcname+'.csv', 'wb') as wcfile:
wcwriter = csv.writer(wcfile)
wcwriter.writerows([[u'Letter', u'Number']])
for k, v in wordcount.items():
wcwriter.writerows([[k, v]])
UTF-8 编码的字节可以很好地打印到屏幕或写入文件,但这只是因为您的屏幕(终端或控制台)和任何读取文件的内容也能理解 UTF-8。
UTF-8 编码每个代码点使用 一个或多个字节。迭代不是逐个代码点而是逐字节地遍历数据代码点。所以字符 'å'
被编码为 UTF8 为两个字节,C3 和 A5。尝试将这两个字节作为字母处理会产生问题:
>>> 'å'
'\xc3\xa5'
>>> for byte in 'å':
... print repr(byte)
...
'\xc3'
'\xa5'
你应该解码到unicode
值,这样Python知道字节编码的代码点,或者你已经有Unicode的地方,不编码:
>>> for codepoint in 'å'.decode('utf8'):
... print repr(codepoint), codepoint
...
u'\xe5' å
当您尝试对已经编码的字节进行编码时,会导致您的异常。 Python 试图通过首先将字节解码为 Unicode 来提供帮助,以便它可以遵守并编码回字节,但它只能使用默认的 ASCII 编码来实现。这就是为什么你在尝试使用 encode()
:
时得到 UnicodeDecodeError
(注意那里的 Decode
)
>>> 'å'.encode('utf8')
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
UnicodeDecodeError: 'ascii' codec can't decode byte 0xc3 in position 0: ordinal not in range(128)
一般来说,您希望尽可能将文本视为 Unicode。实施 Unicode sandwich,尽早从字节解码为 Unicode,并且仅在将数据写回文件时才编码,越晚越好。您正在处理的 JSON 数据已经是 Unicode,因此您只需要在生成 CSV 行时编码为 UTF8,但不是更早的。
在这种情况下,这意味着您应该不编码text
:
for statuses in jres.get('statuses'): # jres is a json format response returned from a API call request
text = statuses['text']
而是仅在将其传递给 CSV 编写器时对其进行编码:
twwriter.writerows([[td, text.encode('utf8'), name, loc, city, province]])
您可能想研究一下 Unicode 和编码之间的区别,以及它们与 Python 的关系:
即使使用解码的 utf-8,Python 似乎也将表情符号等分成多个代码点。我使用以下函数解决了这个问题:
# ustr must be "decoded" unicode string, e.g. u""
def each_utf8_char(ustr, pointer=0):
ustr = ustr.encode('utf-8')
slen = len(ustr)
char = ustr[pointer] if slen > pointer else False
while char:
charVal = ord(char)
if charVal < 128:
bytes = 1
elif charVal < 224:
bytes = 2
elif charVal < 240:
bytes = 3
elif charVal < 248:
bytes = 4
elif charVal == 252:
bytes = 5
else:
bytes = 6
yield ustr[pointer:pointer+bytes].decode('utf-8')
pointer += bytes
char = ustr[pointer] if slen > pointer else False
它是一个生成器,所以你可以这样使用它:
my_ustr = u' Cheers!'
for char in each_utf8_char(my_ustr):
print char
我有一个utf-8编码的字符串(主要是中文+一些英文),想运行算一个字母。 (类似于英语单词计数)。
所以我用了
for letter in text: # text is a utf-8 encoded str
但我不确定 'letter' 我得到了什么。 'text' 在屏幕上打印和写入 csv 都很好。但是 'for letter in text' 中的 'letter' 在屏幕和 csv 文件中看起来都崩溃了。我认为这肯定是与编码相关的一些问题,但是在这里和那里添加 .encode('utf-8')
并不能解决问题并且 return 像
UnicodeDecodeError: 'ascii' codec can't decode byte 0x83 in position 0: ordinal not in range(128)
我的意思是下面的代码没有 return 错误但是字母看起来都崩溃了,当我添加 .encode('utf-8') 至
打印 letter.encode('utf-8')
或 wcwriter.writerows([[k.encode('utf-8'), v]])
# -*- coding: utf-8 -*-
...
with open(fname+'.csv', 'wb') as twfile:
twwriter = csv.writer(twfile)
twwriter.writerows([[u'Date/Time', u'Text', u'ID', u'Location', u'City', u'Province']])
for statuses in jres.get('statuses'): # jres is a json format response returned from a API call request
text = statuses.get('text').encode('utf-8')
if keyword in text:
td = statuses.get('created_at').encode('utf-8')
name = statuses.get('user').get('screen_name').encode('utf-8')
loc = statuses.get('user').get('location').encode('utf-8')
city = statuses.get('user').get('city').encode('utf-8')
province = statuses.get('user').get('province').encode('utf-8')
twwriter.writerows([[td, text, name, loc, city, province]])
keycount += 1
# this is the problematic part. I'm not sure exactly what data type or encoding I'm getting for 'letter' below
for letter in text:
if letter not in dismiss:
print letter # this will print a lot of crushed letters
if letter not in wordcount:
wordcount[letter] = 1
else:
wordcount[letter] += 1
with open(wcname+'.csv', 'wb') as wcfile:
wcwriter = csv.writer(wcfile)
wcwriter.writerows([[u'Letter', u'Number']])
for k, v in wordcount.items():
wcwriter.writerows([[k, v]])
UTF-8 编码的字节可以很好地打印到屏幕或写入文件,但这只是因为您的屏幕(终端或控制台)和任何读取文件的内容也能理解 UTF-8。
UTF-8 编码每个代码点使用 一个或多个字节。迭代不是逐个代码点而是逐字节地遍历数据代码点。所以字符 'å'
被编码为 UTF8 为两个字节,C3 和 A5。尝试将这两个字节作为字母处理会产生问题:
>>> 'å'
'\xc3\xa5'
>>> for byte in 'å':
... print repr(byte)
...
'\xc3'
'\xa5'
你应该解码到unicode
值,这样Python知道字节编码的代码点,或者你已经有Unicode的地方,不编码:
>>> for codepoint in 'å'.decode('utf8'):
... print repr(codepoint), codepoint
...
u'\xe5' å
当您尝试对已经编码的字节进行编码时,会导致您的异常。 Python 试图通过首先将字节解码为 Unicode 来提供帮助,以便它可以遵守并编码回字节,但它只能使用默认的 ASCII 编码来实现。这就是为什么你在尝试使用 encode()
:
UnicodeDecodeError
(注意那里的 Decode
)
>>> 'å'.encode('utf8')
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
UnicodeDecodeError: 'ascii' codec can't decode byte 0xc3 in position 0: ordinal not in range(128)
一般来说,您希望尽可能将文本视为 Unicode。实施 Unicode sandwich,尽早从字节解码为 Unicode,并且仅在将数据写回文件时才编码,越晚越好。您正在处理的 JSON 数据已经是 Unicode,因此您只需要在生成 CSV 行时编码为 UTF8,但不是更早的。
在这种情况下,这意味着您应该不编码text
:
for statuses in jres.get('statuses'): # jres is a json format response returned from a API call request
text = statuses['text']
而是仅在将其传递给 CSV 编写器时对其进行编码:
twwriter.writerows([[td, text.encode('utf8'), name, loc, city, province]])
您可能想研究一下 Unicode 和编码之间的区别,以及它们与 Python 的关系:
即使使用解码的 utf-8,Python 似乎也将表情符号等分成多个代码点。我使用以下函数解决了这个问题:
# ustr must be "decoded" unicode string, e.g. u""
def each_utf8_char(ustr, pointer=0):
ustr = ustr.encode('utf-8')
slen = len(ustr)
char = ustr[pointer] if slen > pointer else False
while char:
charVal = ord(char)
if charVal < 128:
bytes = 1
elif charVal < 224:
bytes = 2
elif charVal < 240:
bytes = 3
elif charVal < 248:
bytes = 4
elif charVal == 252:
bytes = 5
else:
bytes = 6
yield ustr[pointer:pointer+bytes].decode('utf-8')
pointer += bytes
char = ustr[pointer] if slen > pointer else False
它是一个生成器,所以你可以这样使用它:
my_ustr = u' Cheers!'
for char in each_utf8_char(my_ustr):
print char