使用nltk对unicode进行分词
我有一些文本文件,这些文件使用的是utf-8编码,里面有像'ö'、'ü'这样的字符。我想从这些文件中提取文本,但我发现分词器(tokenizer)工作得不太好。如果我使用标准的nltk分词器:
f = open('C:\Python26\text.txt', 'r') # text = 'müsli pöök rääk'
text = f.read()
f.close
items = text.decode('utf8')
a = nltk.word_tokenize(items)
输出结果是:[u'\ufeff', u'm', u'\xfc', u'sli', u'p', u'\xf6', u'\xf6', u'k', u'r', u'\xe4', u'\xe4', u'k']
而Punkt分词器似乎表现得更好:
f = open('C:\Python26\text.txt', 'r') # text = 'müsli pöök rääk'
text = f.read()
f.close
items = text.decode('utf8')
a = PunktWordTokenizer().tokenize(items)
输出结果是:[u'\ufeffm\xfcsli', u'p\xf6\xf6k', u'r\xe4\xe4k']
不过在第一个词前面还是有个'\ufeff',我不知道该怎么处理(其实我可以把它去掉)。我哪里做错了呢?非常感谢大家的帮助。
3 个回答
UFEE代码是一个“零宽度不换行空格”字符,这个字符在re
模块中不被视为普通空格。因此,使用正则表达式r'\w+|[^\w\s]+'
的
nltk.RegexpTokenizer(u'\w+|[^\w\s\ufeff]+')
你需要确保传递给nltk分词器的是unicode字符串。我这边用两个分词器处理你的字符串,得到的结果是完全一样的:
import nltk
nltk.wordpunct_tokenize('müsli pöök rääk'.decode('utf8'))
# output : [u'm\xfcsli', u'p\xf6\xf6k', u'r\xe4\xe4k']
nltk.word_tokenize('müsli pöök rääk'.decode('utf8'))
# output: [u'm\xfcsli', u'p\xf6\xf6k', u'r\xe4\xe4k']
更有可能的是,\uFEFF
这个字符是从文件中读取的内容的一部分。我怀疑它是由分词器插入的。文件开头的\uFEFF
是一个已经不再推荐使用的字节顺序标记(Byte Order Mark)。如果它出现在其他地方,就会被当作一种零宽非断行空格来处理。
这个文件是用微软的记事本写的吗?根据codecs模块的文档:
为了提高UTF-8编码的检测可靠性,微软为其记事本程序发明了一种UTF-8的变种(Python 2.5称之为"utf-8-sig"):在任何Unicode字符写入文件之前,会先写入一个UTF-8编码的字节顺序标记(BOM),它的字节序列看起来是这样的:0xef, 0xbb, 0xbf。
试着用codecs.open()
来读取你的文件。注意使用"utf-8-sig"
编码,这样可以处理掉BOM。
import codecs
f = codecs.open('C:\Python26\text.txt', 'r', 'utf-8-sig')
text = f.read()
a = nltk.word_tokenize(text)
实验:
>>> open("x.txt", "r").read().decode("utf-8")
u'\ufeffm\xfcsli'
>>> import codecs
>>> codecs.open("x.txt", "r", "utf-8-sig").read()
u'm\xfcsli'
>>>