如何解决这个奇怪的Python编码问题?

2024-03-25

我正在对来自网络的字符串语料库执行一些 NLP 任务 - 正如您所期望的,存在编码问题。以下是一些示例:

they don’t serve sushi : the apostrophe in don't is not standard ' but \xe2\x80\x99
Delicious food – Wow   : the hyphen before wow is \xe2\x80\x93

所以现在,我要读取这些行,将它们传递给 NLTK 进行解析,使用解析信息通过 mallet 训练 CRF 模型。

让我们从我在堆栈溢出中随处可见的解决方案开始。这里有一些实验:-

st = "they don’t serve sushi"

st.encode('utf-8')
Out[2]: 'they don\xc3\xa2\xe2\x82\xac\xe2\x84\xa2t serve sushi'

st.decode('utf-8')
Out[3]: u'they don\u2019t serve sushi'

因此,这些只是尝试和错误的尝试,看看某些东西是否可行。

我最终使用了编码后的句子并将其传递到下一部分 - 使用 nltk 进行 pos 标记。posTags = nltk.pos_tag(tokens)它抛出了一个众所周知的丑陋异常:-

 File "C:\Users\user\workspacePy\_projectname_\CRF\FeatureGen.py", line 95, in getSentenceFeatures
    posTags = nltk.pos_tag(tokens)
  File "C:\Users\user\Anaconda\lib\site-packages\nltk\tag\__init__.py", line 101, in pos_tag
    return tagger.tag(tokens)
  File "C:\Users\user\Anaconda\lib\site-packages\nltk\tag\sequential.py", line 61, in tag
    tags.append(self.tag_one(tokens, i, tags))
  File "C:\Users\user\Anaconda\lib\site-packages\nltk\tag\sequential.py", line 81, in tag_one
    tag = tagger.choose_tag(tokens, index, history)
  File "C:\Users\user\Anaconda\lib\site-packages\nltk\tag\sequential.py", line 634, in choose_tag
    featureset = self.feature_detector(tokens, index, history)
  File "C:\Users\user\Anaconda\lib\site-packages\nltk\tag\sequential.py", line 736, in feature_detector
    'prevtag+word': '%s+%s' % (prevtag, word.lower()),
UnicodeDecodeError: 'ascii' codec can't decode byte 0xe2 in position 0: ordinal not in range(128)

当我尝试解码时,它说UnicodeEncodeError: 'ascii' codec can't encode character u'\u2013' in position 42: ordinal not in range(128)在我解码字符串的行中。

所以我目前的解决方案是删除所有非ascii字符。但它完全改变了单词,导致基于一元二元(单词组合)的模型严重丢失数据。

正确的做法应该是什么?


在你的例子中st是一个 str(字节列表)。为此,它以某种形式进行编码(从外观上看是 utf8),但将其视为字节列表,并且您需要知道它是如何编码的以便对其进行解码(尽管 utf8 通常总是一个很好的第一注) )。

>>> st = "they don’t serve sushi"
>>> st
'they don\xe2\x80\x99t serve sushi'
>>> type(st)
<type 'str'>

>>> st.encode('utf8')
UnicodeDecodeError: 'ascii' codec can't decode byte 0xe2 in position 8: ordinal not in range(128)

So st.encode这里是没有意义的。它已经被编码了(从表面上看,解释器将其编码为 utf8)。由于某些疯狂的原因,在 python2 中str.encode首先会decode转换为 unicode,然后encode回到海峡。它默认选择解码为 ascii,但您的数据编码为 utf8。因此,您看到的错误是在编码操作的解码步骤中!它正在查看字节列表e2,80,99并说 - '嗯,那些不是真正的 ASCII 字符'。

让我们从 unicode 数据开始(注意 u):

>>> st = u"they don’t serve sushi"
>>> st
u'they don\u2019t serve sushi'
>>> type(st)
<type 'unicode'>
>>> st.encode('utf8')
'they don\xe2\x80\x99t serve sushi'

确实,这一切都是python2的错。 Python3 不会让你摆脱将 unicode 和 str 视为同一事物的这些恶作剧。

经验法则是;始终在代码中使用 unicode。仅在将数据传入和传出系统时进行编码/解码,并且通常编码为 utf8,除非您有其他特定要求。

在 python2 中你可以确保'data'在你的代码中自动是unicodeu'data'

from __future__ import unicode_literals

>>> st = "they don’t serve sushi"
>>> st
u'they don\u2019t serve sushi'
>>> type(st)
<type 'unicode'>
本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

如何解决这个奇怪的Python编码问题? 的相关文章

随机推荐