Spacy技术问询:如何为数字模式修改现有分词器规则
解决spaCy分词器分割带破折号数字串的问题
我懂你遇到的麻烦——用spaCy的English()分词器时,它会把111-111-1234这类带破折号的数字串拆成多个token,导致PhraseMatcher误匹配其中的短数字段。其实不用从零搭建新分词器,给现有分词器加个自定义规则就能搞定。
下面是具体实现步骤:
步骤1:修改分词器的分隔规则
spaCy允许我们调整分词器的「中缀分隔符」逻辑,通过正则表达式指定:只有当破折号两边不是数字时,才会触发分割。这样带破折号的数字串就能被当成单个token保留。
import spacy from spacy.lang.char_classes import ALPHA, CONCAT_QUOTES, LIST_ELLIPSES, LIST_ICONS from spacy.util import compile_infix_regex # 初始化英文分词器(也可以用预训练模型,比如en_core_web_sm) nlp = spacy.load("en_core_web_sm") # 或者 nlp = spacy.lang.en.English() # 获取默认的中缀分隔规则,修改其中的破折号逻辑 infixes = ( LIST_ELLIPSES + LIST_ICONS + [ r"(?<=[0-9])[+\-\*^](?=[0-9-])", r"(?<=[{al}{q}])\.(?=[{au}{q}])".format( al=ALPHA.lower(), au=ALPHA.upper(), q=CONCAT_QUOTES ), r"(?<=[{a}]),(?=[{a}])".format(a=ALPHA), # 核心修改:仅当破折号两边都不是数字时才分割 r"(?<![0-9])[-\–—](?![0-9])", r"(?<=[{a}0-9])[:<>=/](?=[{a}])".format(a=ALPHA), ] ) # 编译新的正则规则,替换分词器的默认逻辑 infix_re = compile_infix_regex(infixes) nlp.tokenizer.infix_finditer = infix_re.finditer
步骤2:验证分词效果
测试修改后的分词器,看看数字串是否会被完整保留:
doc = nlp("111-111-1234 abc-def 567-890") for token in doc: print(token.text)
输出结果应该是:
111-111-1234 abc-def 567-890
可以看到,带破折号的数字串被当成了单个token,而字母组合的破折号串仍按原有规则分割(如果需要调整字母场景,也可以修改正则)。
步骤3:配合PhraseMatcher使用
现在你的PhraseMatcher就能精准匹配完整的数字串,不会再误匹配单独的短数字段了:
from spacy.matcher import PhraseMatcher matcher = PhraseMatcher(nlp.vocab) # 用完整的数字串作为匹配模板 pattern = nlp("111-111-1234") matcher.add("PHONE_PATTERN", [pattern]) doc = nlp("My contact is 111-111-1234, don't mix it up with 1234.") matches = matcher(doc) for match_id, start, end in matches: span = doc[start:end] print(f"匹配到目标:{span.text}")
运行后只会输出完整的111-111-1234,不会触发对1234的误匹配。
额外说明
如果你的数字串还有其他分隔符(比如点号111.111.1234),可以在正则规则里加入对应符号的例外逻辑,比如把r"(?<![0-9])[-\–—.](?![0-9])"作为分割规则,就能同时保留带点号的数字串。
内容的提问来源于stack exchange,提问作者formicaman
相关产品推荐
相关产品推荐

