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

如何重新还原分词后的email地址,避免@与前后内容被拆分?

邮箱地址分词拆分还原解决方案

问题根因

NLTK默认的word_tokenize遵循Treebank分词规范,会将邮箱地址中的@符号单独拆分为独立token,生成mobydick123、@、gmail.com三个独立分片,而TreebankWordDetokenizer默认没有针对邮箱格式的合并规则,因此无法还原为完整邮箱。

方案1:自定义分词规则,避免邮箱被拆分

优先用正则匹配识别完整邮箱,再对剩余文本做普通分词,从根源避免邮箱被拆分:

from nltk.tokenize.treebank import TreebankWordDetokenizer
from nltk.tokenize import TweetTokenizer
from itertools import groupby
import re

# 自定义支持邮箱识别的分词器
class EmailFriendlyTokenizer:
    def __init__(self):
        self.email_pattern = re.compile(r'[a-zA-Z0-9._%+-]+@[a-zA-Z0-9.-]+\.[a-zA-Z]{2,}')
        self.base_tokenizer = TweetTokenizer()
    
    def tokenize(self, text):
        tokens = []
        last_end = 0
        for match in self.email_pattern.finditer(text):
            start, end = match.span()
            if start > last_end:
                tokens.extend(self.base_tokenizer.tokenize(text[last_end:start]))
            tokens.append(match.group())
            last_end = end
        if last_end < len(text):
            tokens.extend(self.base_tokenizer.tokenize(text[last_end:]))
        return tokens

input_sent = 'Herman Melvilles email is mobydick123@gmail.com'
tokenizer = EmailFriendlyTokenizer()
tokens = tokenizer.tokenize(input_sent)
print(tokens)

# 后续原有逻辑不变
myList = list(filter((']').__ne__, tokens))
myList = list(filter(('[').__ne__, myList))
res = [i[0] for i in groupby(myList)]
my_list = list(map(lambda item: item.replace("W_NLP_PERSON", "[W_NLP_PERSON]").replace('W_NLP_DATE', '[W_NLP_DATE]').replace('W_NLP_IMEI_HARDWARE_ID', '[W_NLP_IMEI_HARDWARE_ID]').replace('W_NLP_IP_ADDRESS', '[W_NLP_IP_ADDRESS]'), res))
my_list = TreebankWordDetokenizer().detokenize(my_list)
print(my_list)

方案2:分词后合并邮箱分片

如果不想修改原有分词逻辑,可以在分词后扫描token列表,合并符合邮箱结构的分片:

from nltk.tokenize.treebank import TreebankWordDetokenizer
from nltk.tokenize import word_tokenize
from itertools import groupby
import re

input_sent = 'Herman Melvilles email is mobydick123@gmail.com'
tokens = word_tokenize(input_sent)
print(tokens)

# 合并邮箱分片逻辑
merged_tokens = []
i = 0
n = len(tokens)
domain_pattern = re.compile(r'[a-zA-Z0-9.-]+\.[a-zA-Z]{2,}')
while i < n:
    if i+2 < n and tokens[i+1] == '@' and domain_pattern.match(tokens[i+2]):
        merged_tokens.append(f"{tokens[i]}{tokens[i+1]}{tokens[i+2]}")
        i += 3
    else:
        merged_tokens.append(tokens[i])
        i += 1

# 后续原有逻辑改用合并后的token列表
myList = list(filter((']').__ne__, merged_tokens))
myList = list(filter(('[').__ne__, myList))
res = [i[0] for i in groupby(myList)]
my_list = list(map(lambda item: item.replace("W_NLP_PERSON", "[W_NLP_PERSON]").replace('W_NLP_DATE', '[W_NLP_DATE]').replace('W_NLP_IMEI_HARDWARE_ID', '[W_NLP_IMEI_HARDWARE_ID]').replace('W_NLP_IP_ADDRESS', '[W_NLP_IP_ADDRESS]'), res))
my_list = TreebankWordDetokenizer().detokenize(my_list)
print(my_list)

方案3:使用spaCy分词

你已导入的spaCy默认分词器本身就支持识别邮箱为独立token,无需额外自定义规则:

from nltk.tokenize.treebank import TreebankWordDetokenizer
from itertools import groupby
import spacy

# 加载轻量英文模型,关闭不需要的管线提升速度
nlp = spacy.load("en_core_web_sm", disable=["parser", "ner", "tagger"])
input_sent = 'Herman Melvilles email is mobydick123@gmail.com'
doc = nlp(input_sent)
tokens = [token.text for token in doc]
print(tokens)

# 后续原有逻辑不变
myList = list(filter((']').__ne__, tokens))
myList = list(filter(('[').__ne__, myList))
res = [i[0] for i in groupby(myList)]
my_list = list(map(lambda item: item.replace("W_NLP_PERSON", "[W_NLP_PERSON]").replace('W_NLP_DATE', '[W_NLP_DATE]').replace('W_NLP_IMEI_HARDWARE_ID', '[W_NLP_IMEI_HARDWARE_ID]').replace('W_NLP_IP_ADDRESS', '[W_NLP_IP_ADDRESS]'), res))
my_list = TreebankWordDetokenizer().detokenize(my_list)
print(my_list)

内容的提问来源于stack exchange,提问作者albusdemens

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.09.29 17:15:03