如何将字符索引转换为 SpaCy 令牌索引?

How to transform character indices to SpaCy token indices?

我正在使用 SpaCy 查找文本中的模式。 对于某些模式(例如单个单词),这很简单,我对结果很满意。 例如,

import re
import spacy
from spacy.matcher import Matcher

nlp = spacy.load("en_core_web_sm")
matcher = Matcher(nlp.vocab)
matcher.add("Month", [[{"TEXT": "January"}]])

doc = nlp("The date 1 January 2022 can also be written as 1/1/2022.") 

for match_id, start, end in matcher(doc):
    match_id_string = matcher.vocab.strings[match_id]
    span = doc[start:end]
    print(match_id_string, span.text, start, end)

将在 doc 中找到“January”作为第四个标记并将其识别为“Month”模式。

对于日期模式,事情要复杂一些。 我使用 SpaCy 来搜索被表述为正则表达式的模式。 添加代码

matcher.add("Date", [[{"TEXT": {"REGEX": "1/1/2022"}}]])

其中“1/1/2022”是一个(非常简单的)正则表达式, 将在上面定义的 doc 中找到日期“1/1/2022” 并将其识别为“日期”模式。 但是添加

matcher.add("Date", [[{"TEXT": {"REGEX": "1 January 2022"}}]])

找不到日期“2022 年 1 月 1 日”。 作为 SpaCy 网站上的 explained 这是因为匹配器只匹配单个标记。 SpaCy提供的解决方案是 “在 doc.text 上与 re.finditer 匹配”:

for match in re.finditer("1 January 2022", doc.text):
    start, end = match.span()
    span = doc.char_span(start, end)
    print(span.text, start, end)

这会发现“2022 年 1 月 1 日”是从索引 9 到 23 的字符范围。

但是,我想将使用 re.finditer 找到的匹配项放入 转换为通常的 SpaCy 格式的匹配项, 这是一个包含匹配 ID 和 tokens 的开始和结束索引的 3 元组 而不是字符范围的开始和结束索引。

问题: 如何将这些字符索引转换为标记索引?

SpaCy 是否提供了执行此操作的方法? 我想那将是理想的,但我没有找到。 否则,还有其他聪明的工具可以做到这一点吗? 我可以试着从头开始或多或少地做一个, 但这感觉就像重新发明轮子。

您可以从跨度中获取令牌索引。

for match in re.finditer("1 January 2022", doc.text):
    start, end = match.span()
    span = doc.char_span(start, end)
    
    match = (match_id, span[0].i, span[-1].i + 1)

此外,如果您尝试匹配文字短语,您可以只使用 EntityRuler 已经支持的 PhraseMatcher - 您只需将字符串作为模式而不是字典传递。