查找字符串中char / word的周围句子

时间:2013-03-20 17:18:26

标签: python regex nltk

我正在尝试使用python从包含给定子字符串的字符串中获取句子。

我可以访问字符串(学术摘要)和包含开始和结束索引的突出显示列表。例如:

{
  abstract: "...long abstract here..."
  highlights: [
    {
      concept: 'a word',
      start: 1,
      end: 10
    }
    {
      concept: 'cancer',
      start: 123,
      end: 135
    }
  ]
}

我循环遍历每个突出显示,在摘要中找到它的起始索引(结尾并不重要,因为我只需要在句子中获取位置),然后以某种方式需要识别索引发生在。

我能够使用nltk.tonenize.sent_tokenize将摘要标记为句子,但通过这样做,我使索引位置无用。

我应该如何解决这个问题?我认为正则表达式是一个选项,但是nltk标记化器似乎是一种很好的方式,这样做不会使用它是一种耻辱。或者以某种方式重置起始索引,通过查找自上一次完整停止后的字符数/感叹号/问号?

3 个答案:

答案 0 :(得分:6)

你是对的,NLTK标记器实际上是你应该在这种情况下使用的,因为它足够强大,可以处理大多数句子的分界,包括用“引用”结束一个句子。您可以执行以下操作(paragraph来自随机生成器):

开头,

from nltk.tokenize import sent_tokenize

paragraph = "How does chickens harden over the acceptance? Chickens comprises coffee. Chickens crushes a popular vet next to the eater. Will chickens sweep beneath a project? Coffee funds chickens. Chickens abides against an ineffective drill."
highlights = ["vet","funds"]
sentencesWithHighlights = []

最直观的方式:

for sentence in sent_tokenize(paragraph):
    for highlight in highlights:
        if highlight in sentence:
            sentencesWithHighlights.append(sentence)
            break

但是使用这种方法我们实际上拥有3x嵌套for循环。这是因为我们首先检查每个sentence,然后检查每个highlight,然后检查sentencehighlight的每个子序列。

我们可以获得更好的效果,因为我们知道每个突出显示的起始索引:

highlightIndices = [100,169]
subtractFromIndex = 0
for sentence in sent_tokenize(paragraph):
    for index in highlightIndices:
        if 0 < index - subtractFromIndex < len(sentence):
            sentencesWithHighlights.append(sentence)
            break
    subtractFromIndex += len(sentence)

在任何一种情况下,我们都会:

sentencesWithHighlights = ['Chickens crushes a popular vet next to the eater.', 'Coffee funds chickens.']

答案 1 :(得分:1)

我假设你的所有句子都以这三个字符中的一个结尾:!?.

如何在高亮显示列表上循环,创建一个正则表达式组:

(?:list|of|your highlights)

然后将整个摘要与此正则表达式进行匹配:

/(?:[\.!\?]|^)\s*([^\.!\?]*(?:list|of|your highlights)[^\.!\?]*?)(?=\s*[\.!\?])/ig

通过这种方式,您可以获得包含每个匹配的第一个子组中至少一个重点的句子(RegExr)。

答案 2 :(得分:0)

另一种选择(虽然很难说可变文本的可靠程度如何),将文本分成一系列句子并对其进行测试:

re.split('(?<=\?|!|\.)\s{0,2}(?=[A-Z]|$)', text)