如何让这个Python2.6函数支持Unicode?

0 投票
1 回答
1814 浏览
提问于 2025-04-16 04:27

我有一个函数,是我从网上的NLTK书第一章修改过来的。这个函数对我很有帮助,但尽管我读过关于Unicode的章节,我还是觉得很困惑。

def openbookreturnvocab(book):
    fileopen = open(book)
    rawness = fileopen.read()
    tokens = nltk.wordpunct_tokenize(rawness)
    nltktext = nltk.Text(tokens)
    nltkwords = [w.lower() for w in nltktext]
    nltkvocab = sorted(set(nltkwords))
    return nltkvocab

前几天我在《查拉图斯特拉如是说》上试了一下,结果把带有变音符号的字母o和u搞乱了。我相信你们中的一些人知道这是为什么。我也确信这很容易解决。我知道这和调用一个将词语重新编码为unicode字符串的函数有关。如果真是这样,那我觉得问题可能不在那个函数定义里,而是在我准备写入文件的地方:

def jotindex(jotted, filename, readmethod):
    filemydata = open(filename, readmethod)
    jottedf = '\n'.join(jotted)
    filemydata.write(jottedf)
    filemydata.close()
    return 0

我听说我需要在从文件读取字符串后将其编码为unicode。我试着这样修改函数:

def openbookreturnvocab(book):
    fileopen = open(book)
    rawness = fileopen.read()
    unirawness = rawness.decode('utf-8')
    tokens = nltk.wordpunct_tokenize(unirawness)
    nltktext = nltk.Text(tokens)
    nltkwords = [w.lower() for w in nltktext]
    nltkvocab = sorted(set(nltkwords))
    return nltkvocab

但是当我在匈牙利语上使用它时出现了这个错误。而在德语上使用时没有错误。

>>> import bookroutines
>>> elles1 = bookroutines.openbookreturnvocab("lk1-les1")
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
  File "bookroutines.py", line 9, in openbookreturnvocab
    nltktext = nltk.Text(tokens)
  File "/usr/lib/pymodules/python2.6/nltk/text.py", line 285, in __init__
    self.name = " ".join(map(str, tokens[:8])) + "..."
UnicodeEncodeError: 'ascii' codec can't encode character u'\xe1' in position 4: ordinal not in range(128)

我这样修复了存储数据的函数:

def jotindex(jotted, filename, readmethod):
    filemydata = open(filename, readmethod)
    jottedf = u'\n'.join(jotted)
    filemydata.write(jottedf)
    filemydata.close()
    return 0

然而,当我尝试存储德语时又出现了这个错误:

Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
  File "bookroutines.py", line 23, in jotindex
    filemydata.write(jottedf)
UnicodeEncodeError: 'ascii' codec can't encode character u'\xf6' in position 414: ordinal not in range(128)
>>> 

...这就是你尝试写入u'\n'.join的数据时得到的结果。

>>> jottedf = u'/n'.join(elles1)
>>> filemydata.write(jottedf)
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
UnicodeEncodeError: 'ascii' codec can't encode character u'\xf6' in position 504: ordinal not in range(128)

1 个回答

4

对于你从文件中读取的每个字符串,如果它们是UTF-8格式的,你可以通过调用 rawness.decode('utf-8') 来把它们转换成unicode格式。这样你就会得到unicode对象。另外,我不太清楚“jotted”是什么,但你可能需要确保它是一个unicode对象,然后用 u'\n'.join(jotted) 来处理。

更新:

看起来NLTK库对unicode对象不太友好。那么你需要确保使用的是UTF-8编码的字符串实例。试试这个:

tokens = nltk.wordpunct_tokenize(unirawness)
nltktext = nltk.Text([token.encode('utf-8') for token in tokens])

还有这个:

jottedf = u'\n'.join(jotted)
filemydata.write(jottedf.encode('utf-8'))

不过如果jotted真的只是一个UTF-8编码的字符串列表,那你就不需要这些,直接用这个就可以了:

jottedf = '\n'.join(jotted)
filemydata.write(jottedf)

顺便说一下,NLTK在处理unicode和编码方面似乎不太谨慎(至少在演示中是这样)。所以最好小心点,检查一下它是否正确处理了你的数据。此外,这可能是你在处理匈牙利文本时出现错误,而在处理德语文本时没有错误的原因,检查你的编码

撰写回答