如何向spaCy令牌生成器添加自定义规则以分解单个令牌中的HTML?

时间:2020-06-26 18:42:33

标签: python parsing spacy

我知道有很多资源可以解决此问题,但是我无法让spaCy完全按照自己的意愿做...

我想向spaCy令牌生成器添加规则,以便文本中的HTML标签(例如<br/>等)将成为单个令牌。 我现在正在使用“ merge_noun_chunks”管道,因此我得到了这样的令牌:
"documentation<br/>The Observatory Safety System"(这是一个令牌)

我想添加一条规则,以便将其分为3个令牌:
"documentation", "<br/>", "The Observatory Safety System"
我已经查了很多资源:herealso here ...但是我无法解决这个问题

我已经尝试过了:

    
    infix_re = re.compile(r'''<[\w+]\/>''')
    prefix_re = compile_prefix_regex(nlp.Defaults.prefixes)
    suffix_re = compile_suffix_regex(nlp.Defaults.suffixes)

    return Tokenizer(nlp.vocab, prefix_search=prefix_re.search,
                                suffix_search=suffix_re.search,
                                infix_finditer=infix_re.finditer,
                                token_match=None)

我不确定我确切了解更改中缀的作用。我还应该从前缀as suggested here中删除<吗?

谢谢

1 个答案:

答案 0 :(得分:1)

实现这一目标的一种方法似乎涉及使分词器同时具备

  1. 分解包含没有空格的标记的标记,以及
  2. “块状”标签序列作为单个标记。

要像示例中那样拆分标记,您可以修改标记器中缀(在 the manner described here 中):

infixes = nlp.Defaults.infixes + [r'([><])']
nlp.tokenizer.infix_finditer = spacy.util.compile_infix_regex(infixes).finditer

为确保标签被视为单个标记,您可以使用“特殊情况”(参见 the tokenizer overviewmethod docs)。您可以为打开的、关闭的和空的标签添加特殊情况,例如:

# open and close
for tagName in "html body i br p".split():
    nlp.tokenizer.add_special_case(f"<{tagName}>", [{ORTH: f"<{tagName}>"}])    
    nlp.tokenizer.add_special_case(f"</{tagName}>", [{ORTH: f"</{tagName}>"}])    

# empty
for tagName in "br p".split():
    nlp.tokenizer.add_special_case(f"<{tagName}/>", [{ORTH: f"<{tagName}/>"}])    

综合:

import spacy
from spacy.symbols import ORTH

nlp = spacy.load("en_core_web_trf")
infixes = nlp.Defaults.infixes + [r'([><])']
nlp.tokenizer.infix_finditer = spacy.util.compile_infix_regex(infixes).finditer

for tagName in "html body i br p".split():
    nlp.tokenizer.add_special_case(f"<{tagName}>", [{ORTH: f"<{tagName}>"}])    
    nlp.tokenizer.add_special_case(f"</{tagName}>", [{ORTH: f"</{tagName}>"}])    

for tagName in "br p".split():
    nlp.tokenizer.add_special_case(f"<{tagName}/>", [{ORTH: f"<{tagName}/>"}])    

这似乎产生了预期的结果。例如,申请...

text = """<body>documentation<br/>The Observatory <p> Safety </p> System</body>"""
print("Tokenized:")
for t in nlp(text):
    print(t)

... 将单独打印整个标签:

# ... snip
documentation
<br/>
The
# ... snip

我发现 the tokenizer's explain method 在这方面很有帮助。它为您详细说明了标记化的原因。