spaCy的正则表达式与Python的正则表达式不同。

5

我有以下文本

text = 'Monday to Friday 12 midnight to 5am 30% . Midnight Friday to 6am Saturday 30% . 9pm Saturday to Midnight Saturday 25% . Midnight Saturday to 6am Sunday 100% . 6am Sunday to 9pm Sunday 50%'

当我使用普通正则表达式时,我获得了以下结果

import re
regex = '\d{1}[a|p]m'
re.findall(regex, text)

# Returned:
['5am', '6am', '9pm', '6am', '6am', '6pm']

然而,当我在 spaCy 中使用相同的 正则表达式 时,却什么也没有得到。

from spacy.matcher import Matcher
nlp = spacy.load('en_core_web_lg')

matcher = Matcher(nlp.vocab)
pattern = [{'TEXT': {'REGEX': '\d{1}[a|p]m'}}]
matcher.add('TIME', None, pattern)

doc = nlp(text)
matches = matcher(doc)

for match_id, start, end in matches:
    matched_span = doc[start:end]
    print(matched_span.sent.text)

这是否意味着我们不能在spaCy中使用普通的正则表达式?如果是这样,你知道我在哪里可以学习spaCy的特殊正则表达式语法吗?谢谢。


3
补充信息: "normal" 的正则表达式可以是 regex = r'\d[ap]m'。(说明:FYI 是“供参考”的意思,r 表示使用原始字符串,\d 匹配数字,[ap] 匹配 a 或 p。) - Wiktor Stribiżew
3
根据文档,您似乎在错误地使用它:“当使用REGEX运算符时,请记住它是针对单个标记而不是整个文本进行操作的。您提供的每个表达式都将在一个标记上匹配。如果您需要在整个文本上进行匹配,请参阅正则表达式匹配整个文本上的详细信息。” - MonkeyZeus
@WiktorStribiżew 虽然你在技术上是正确的,但这是对一个很可能不正确的正则表达式的更正,因为它排除了上午11点和下午12点。 - MonkeyZeus
谢谢@MonkeyZeus。一开始我有点困惑,不理解你所说的single token, not the whole text是什么意思,因为我认为6am、6pm等都是单个token。直到读了Wiktor的答案,我才明白spaCy将它们视为2个而不是1个token。我想知道为什么spaCy这样做,因为这对我来说似乎不是“自然”的? - Nemo
1个回答

13

请记住,在这里数字将与字母分开,看一下测试:

doc = nlp("1pm")
print([token.text for token in doc]) # => ['1', 'pm']

根据Spacy文档,如果spaCy的分词结果与模式中定义的标记不匹配,则该模式将不会产生任何结果。您需要使用基于规则的匹配来定义自己的实体。
pattern = [{'LIKE_NUM': True}, {'LOWER': {'REGEX' : '^[ap]m$'}}]

然后将它添加到匹配器(matcher)中:

matcher.add('TIME', None, pattern)

并获取匹配项:

for match_id, start, end in matches:
    span = doc[start:end]  # The matched span
    print(span.text)

完整演示:

import spacy
from spacy.matcher import Matcher

nlp = spacy.load("en_core_web_sm")

text = 'Monday to Friday 12 midnight to 5am 30% . Midnight Friday to 6am Saturday 30% . 9pm Saturday to Midnight Saturday 25% . Midnight Saturday to 6am Sunday 100% . 6am Sunday to 9pm Sunday 50%'
doc = nlp(text)

matcher = Matcher(nlp.vocab)
pattern = [{'LIKE_NUM': True}, {'LOWER': {'REGEX' : '^[ap]m$'}}]
matcher.add('TIME', None, pattern)

matches = matcher(doc)
print([doc[start:end] for match_id, start, end in matches])
#=> [5am, 6am, 9pm, 6am, 6am, 9pm]

嗨,Wiktor,感谢你不仅提供了解决方案,还向我展示了如何下次排除问题。非常感谢你的帮助。正则表达式本身就是一个挑战(不仅对我而言,我猜很多其他人也是),然后将其与spaCy结合起来就超出了我的能力范围!如果你想匹配模式,你会使用哪个:正则表达式还是spaCy,以及原因是什么? - Nemo
1
@Nemo Spacy比仅使用正则表达式要强大得多,因此它取决于您的需求。如果您需要提取、替换、删除或标记一些已知的更简单的模式,那么可以使用正则表达式。如果您需要更具体和语言感知的分词,并且需要整个NLP的强大功能,则应使用Spacy。 - Wiktor Stribiżew

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接