You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何让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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.05 16:07:47