【问题标题】:Using a regular expression to find all noun phrases in a paragraph following the occurrence of a specific phrase使用正则表达式查找段落中出现特定短语后的所有名词短语
【发布时间】:2016-03-13 22:36:30
【问题描述】:

我有一个段落数据框,我将其 (*can) 拆分为单词标记和句子标记,并希望在短语“contribute to”或“donate to”的任何实例之后找到所有名词短语发生。

或者实际上是某种形式,所以:

"Contributions are welcome to be made to the charity of your choice." 

---> would return: "the charity of your choice"

"blah blah blah donations, in honor of Firstname Lastname, can be made to ABC Foundation"

---> would return: "ABC Foundation"

我创建了一个正则表达式变通方案,可以在大约 90% 的时间捕获正确的短语...见下文:

text = nltk.Text(nltk.word_tokenize(x))
donation = TokenSearcher(text).findall(r"<\.> <.*>{,15}? <donat.*|contrib.*> <.*>*? <to> (<.*>+?) <\.|\,|\;> ")
donation = [' '.join(tokens) for tokens in donation]
return donation

我想清理该正则表达式以摆脱“{,15}”要求,因为它缺少一些我需要的值。但是,我对“贪婪”的表达方式不太满意,无法让它正常工作。

所以这句话:

While she lived a full life , had many achievements and made many 
**contributions** , FirstName is remembered by most for her cheerful smile ,
colorful track suits , and beautiful necklaces hand made by daughter FirstName .
FirstName always cherished her annual visit home for Thanksgiving to visit
brother FirstName LastName

正在返回:“visit brother FirstName Lastname”,因为之前提到了贡献,即使“to”这个词在 15 个单词之后出现。

【问题讨论】:

  • "即使 'to' 这个词出现在 15 个单词之后。"好吧。这就是.* 所做的。它明确匹配任意数量的字符。
  • 我认为后面的 "{,15}" 将其限制为最多 15 个单词。
  • 这发生在“contrib.*”匹配之前。
  • 投票结束的范围太广了,因为这个不是单一的问题没有单一的答案。
  • @BenPrice 这就是为什么您的“0-15 字”量词没有按您预期的方式工作的原因。 s24.postimg.org/kbgu86crp/words.png

标签: python regex nlp nltk findall


【解决方案1】:
(?:contrib|donat|gifts)(?=[^\.]+\bto\b[^\.]+).*to\s([^\.]+)

Example 如果有效并满足您的需求,请告诉我,我将解释我的正则表达式。

【讨论】:

  • 对不起,我无法回答如何在您的程序代码中应用它并判断您尝试使用的函数是否支持所有使用的表达式。
  • 所以我实现了这个,但我得到了一个“错误:没有什么可重复的”,我用谷歌搜索了一下,看起来它是 python 正则表达式实现中的一个错误,但我不确定究竟是什么导致了它。
  • 反斜杠在字符范围内不能作为转义符(也不需要)。 [^\.] 匹配除句点或反斜杠之外的所有内容。
【解决方案2】:

您似乎在为如何将搜索条件限制为一个句子而苦恼。因此,只需使用 NLTK 将您的文本分成句子(它可以做得比只看句号要好得多),您的问题就会消失。

sents = nltk.sent_tokenize(x)  # `x` is a single string, as in your example
recipients = []
for sent in sents:
    m = re.search(r"\b(contrib|donat).*?\bto\b([^.,;]*)", sent)
    if m:
        recipients.append(m.group(2).strip())

对于进一步的工作,我还建议您使用比 Text 更好的工具,该工具旨在用于简单的交互式探索。如果您确实想对您的文本做更多的事情,nltk 的PlaintextCorpusReader 是您的朋友。

【讨论】:

  • 感谢@Ben,这部分是必不可少的(而且是标准的;不知何故,我在输入这个答案时放弃了它。)
  • 所以这很好用,但是当我执行 send_tokenize 时,它​​的结尾句会在“博士”之类的词之后。和“圣”。和“山”。所以像“代替鲜花,可以为乔治城大学 Giuseppe Giaccone 博士的研究进行纪念捐款”这样的短语只返回“博士的研究”。您是否知道是否有任何类型的解决方法可以解决缩写问题或以不同的方式将句子标记为一个总标记?
  • 现在可以了吗?我尝试了这个确切的句子,句子标记器处理了“博士”。正确地作为不结束一个句子。缩写正是句子标记器旨在处理的那种事情。当然,基于 your 正则表达式的 NP 提取会在下一个句点停止(它会提取 [^.,;]*),因此尽管句子是完整的,但您只提取“名词短语”直到下一个标点符号。为了获得更好的性能,请将您的正则表达式方法替换为 POS 标记和/或 NP 分块器(参见 nltk 书籍的chapter 7)。
  • 感谢您的建议,这肯定是下一步。你知道是否有办法调整正则表达式,使它只捕获到句子结尾的所有内容?另外,关于在 Dr. 和 St. 上工作的 sent_tokenizer 是对的,我认为它只是把 Mt. 搞砸了。
  • 好吧,我刚刚从最后一个字符括号中删除了句点......这似乎有效,所以现在它只检查逗号或分号,或者只捕获句子的其余部分。 re.search(r"\b(contrib|donat).*?\bto\b([^,;]*)", 发送)。感谢您的所有帮助
猜你喜欢
  • 1970-01-01
  • 2018-07-05
  • 2013-11-09
  • 2017-08-18
  • 1970-01-01
  • 2014-08-14
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多