如何让NLTK分词器将带引号文本中的引号视为普通标点?
问题描述
用NLTK的word_tokenize处理带引号的文本时,引号的分词结果不符合预期:
- 双引号被转换成``和''这种左右引号形式,而非单独的标点
- 开头的单引号会和相邻单词合并(比如
'make被当作一个整体)
测试文本(test_file.txt):
This text has some "quotation marks" to really 'make things' difficult.
测试脚本:
from nltk.tokenize import word_tokenize with open("test_file.txt", encoding='utf-8') as test_file: test_text = test_file.read() print(word_tokenize(test_text))
实际输出:
['This', 'text', 'has', 'some', '``', 'quotation', 'marks', "''", 'to', 'really', "'make", 'things', "'", 'difficult', '.']
优雅解决方案
方法1:自定义正则分词器(推荐)
直接用RegexpTokenizer定义规则,把单/双引号当作独立的标点符号,和单词、其他标点分开处理,简单直接。
示例代码:
from nltk.tokenize import RegexpTokenizer # 正则规则:匹配单词、双引号、单引号、其他非空白非单词的标点 tokenizer = RegexpTokenizer(r'\w+|[\"\']|[^\w\s]') with open("test_file.txt", encoding='utf-8') as test_file: test_text = test_file.read() tokens = tokenizer.tokenize(test_text) print(tokens)
输出结果(符合预期):
['This', 'text', 'has', 'some', '"', 'quotation', 'marks', '"', 'to', 'really', "'", 'make', 'things', "'", 'difficult', '.']
方法2:修改Treebank分词器规则
word_tokenize底层依赖TreebankWordTokenizer,可以修改它的内置规则,移除引号的特殊转换逻辑,让引号按普通标点分词。
示例代码:
from nltk.tokenize.treebank import TreebankWordTokenizer import re # 初始化分词器,复制默认规则并调整引号处理 tokenizer = TreebankWordTokenizer() # 移除原有将双引号转为``/''的规则,保留其他标点处理逻辑 tokenizer.PUNCTUATION = [ (re.compile(r'([^\.])(\.)([\]\)}>"\'' r"»”’ ']+)\s*$"), r'\1 \2 \3'), (re.compile(r'([:,])([^\d])'), r'\1 \2'), (re.compile(r'([:,])$'), r'\1 '), (re.compile(r'\.{3}'), r' ... '), (re.compile(r'[;@#$%&]'), r' \g<0> '), (re.compile(r'([^\']) \' '), r'\1 \' '), (re.compile(r'([^n])\'t '), r'\1 n\'t '), (re.compile(r'([^n])\'T '), r'\1 N\'T '), (re.compile(r'\'([sSmMdD]) '), r" '\1 "), (re.compile(r'\'ll '), r" 'll "), (re.compile(r'\'LL '), r" 'LL "), (re.compile(r'\'re '), r" 're "), (re.compile(r'\'RE '), r" 'RE "), (re.compile(r'\'ve '), r" 've "), (re.compile(r'\'VE '), r" 'VE "), (re.compile(r'\'m '), r" 'm "), (re.compile(r'\'M '), r" 'M "), (re.compile(r'\'d '), r" 'd "), (re.compile(r'\'D '), r" 'D "), (re.compile(r'\'s '), r" 's "), ] # 添加规则:把双引号单独分词 tokenizer.PUNCTUATION.append((re.compile(r'\"'), r' " ')) # 添加规则:把开头/空格后的单引号单独分词,不和后面的单词合并 tokenizer.PUNCTUATION.append((re.compile(r'^\'([a-zA-Z])'), r" ' \1")) tokenizer.PUNCTUATION.append((re.compile(r'\s\'([a-zA-Z])'), r" ' \1")) with open("test_file.txt", encoding='utf-8') as test_file: test_text = test_file.read() # 分词后清理空字符串 tokens = [t.strip() for t in tokenizer.tokenize(test_text) if t.strip()] print(tokens)
这个方法更贴近NLTK原生分词的逻辑,适合需要保留其他Treebank分词规则的场景。
内容的提问来源于stack exchange,提问作者AdeDoyle
相关产品推荐
相关产品推荐

