匹配文本中存储的关键字/短语

时间:2009-12-04 13:06:10

标签: python mysql regex django

我有一个包含大约1000个关键字/短语(一到四个字长)的数据库表 - 这个表很少变化,所以我可以将数据提取到更有用的东西(比如正则表达式?) - 所以这不是查找/猜测基于自然语言处理的关键词..

然后我让用户在表格中输入一些文字,我想与我的关键词和短语进行匹配。

程序将存储指向文本旁边匹配的每个短语的链接。

因此,如果我们针对此处的一些短语对此问题文本运行算法,我们会得到如下结果:

{"inputting some text" : 1,
 "extract the data" : 1,
 "a phrase not here" : 0}

我有什么选择?

  1. 编译正则表达式
  2. 某种SQL查询
  3. 第三种方式?
  4. 请记住,有1000个可能的短语..

    我正在使用MySQL运行Django / Python。

    编辑:我目前正在这样做:

    >>> text_input = "This is something with first phrase in and third phrase" 
    >>> regex = "first phrase|second phrase|third phrase" 
    >>> p = re.compile(regex, re.I) 
    >>> p.findall(text_input)
    ['first phrase','third phrase']
    

6 个答案:

答案 0 :(得分:1)

此作业的算法为Aho-Corasick ...请参阅底部的链接,该链接指向Python的C扩展名。

答案 1 :(得分:0)

如果我理解正确,你有一组独特的字符串,你想要比较输入字符串。在这种情况下,您可以使用set来存储处理结果和db​​值。然后比较可以如下进行:

>>> db = {'abc', 'def', 'jhi', 'asdf'}
>>> inpt = {'abc', 'tmp'}
>>> db & inpt
{'abc'}

进一步转换为字典是微不足道的。

答案 2 :(得分:0)

只是抬头......你可能对django's support for regex in queries

感兴趣

来自链接的django文档的示例:

Entry.objects.get(title__regex=r'^(An?|The) +')

答案 3 :(得分:0)

以下是SilentGhost答案的细微变化。您逐行加载关键字。将它们存放在一组中。对于在用户输入中找到的每个关键字,会增加结果中的相应条目。

keyword_file = StringIO("""inputting some text
    extract the data
    a phrase not here""")

keywords = set(line.strip() for line in keyword_file)

results = defaultdict(int)
for phrase in keywords:
    if userinput.find(phrase) != -1:
        results[phrase] += 1

print results

希望这能指出你正确的方向。不完全确定这是你问的问题,但这是我最好的猜测。

你关心速度吗?你为什么不喜欢你现在使用的方法?你的方法有用吗?

答案 4 :(得分:0)

一旦你形成了你的模式,例如(first phrase)|(the second)|(and another) with 我指出的括号)并将其编译成正则表达式对象r,这是一个很好的循环方式匹配并确定它匹配的是:

class GroupCounter(object):
  def __init__(self, phrases):
    self.phrases = phrases
    self.counts = [0] * len(phrases)
  def __call__(self, mo):
    self.counts[mo.lastindex - 1] += 1
    return ''
  def asdict(self):
    return dict(zip(self.phrases, self.counts))

g = GroupCounter(['first phrase', 'the second', 'and another'])
r.sub(g, thetext)
print g.asdict()

让GroupCounter实例也构建正则表达式对象也是合理的,因为它确实需要与正则表达式本身中出现的顺序相同的短语列表。

答案 5 :(得分:0)

如果您有1000个短语,并且您正在搜索输入字符串以查找哪些短语是子字符串,那么您可能不会对使用大型正则表达式所获得的性能感到满意。 trie需要更多的工作来实现,但效率更高:正则表达式a|b|c|d|e对给定输入字符串中的每个字符执行五次测试,而trie只执行一次。你可以想象也可以使用像Plex那样产生DFA的词法分析器。

修改

我今天早上好像在拖延。试试这个:

    class Trie(object):
        def __init__(self):
            self.children = {}
            self.item = None
        def add(self, item, remainder=None):
            """Add an item to the trie."""
            if remainder == None:
                remainder = item
            if remainder == "":
                self.item = item
            else:
                ch = remainder[0]
                if not self.children.has_key(ch):
                    self.children[ch] = Trie()
                self.children[ch].add(item, remainder[1:])
        def find(self, word):
            """Return True if word is an item in the trie."""
            if not word:
                return True
            ch = word[0]
            if not self.children.has_key(ch):
                return False
            return self.children[ch].find(word[1:])
        def find_words(self, word, results=None):
            """Find all items in the trie that word begins with."""
            if results == None:
                results = []
            if self.item:
                results.append(self.item)
            if not word:
                return results
            ch = word[0]
            if not self.children.has_key(ch):
                return results
            return self.children[ch].find_words(word[1:], results)

快速测试(words.txt是BSD单词文件,一个非常方便的东西 - 它包含大约240,000个单词):

>>> t = Trie()
>>> with open(r'c:\temp\words.txt', 'r') as f:
        for word in f:
            t.add(word.strip())

我的机器需要大约15秒钟。然而,这几乎是瞬间的:

>>> s = "I played video games in a drunken haze."
>>> r = []
>>> for i in range(len(s)):
        r.extend(t.find_words(s[i:]))
>>> r
['I', 'p', 'play', 'l', 'la', 'lay', 'a', 'ay', 'aye', 'y', 'ye', 'yed', 'e', 'd', 'v', 'video', 'i', 'id', 'ide', 'd', 'de', 'e', 'o', 'g', 'ga', 'gam', 'game', 'a', 'am', 'ame', 'm', 'me', 'e', 'es', 's', 'i', 'in', 'n', 'a', 'd', 'drunk', 'drunken', 'r', 'run', 'u', 'un', 'unken', 'n', 'k', 'ken', 'e', 'en', 'n', 'h', 'ha', 'haze', 'a', 'z', 'e']

是的,unken位于words.txt中。我不明白为什么。

哦,我确实尝试与正则表达式进行比较:

 >>> import re
 >>> with open(r'c:\temp\words.txt', 'r') as f:
         p = "|".join([l.strip() for l in f])

 >>> p = re.compile(p)

 Traceback (most recent call last):
  File "<pyshell#250>", line 1, in <module>
    p = re.compile(p)
  File "C:\Python26\lib\re.py", line 188, in compile
    return _compile(pattern, flags)
  File "C:\Python26\lib\re.py", line 241, in _compile
    p = sre_compile.compile(pattern, flags)
  File "C:\Python26\lib\sre_compile.py", line 529, in compile
    groupindex, indexgroup
OverflowError: regular expression code size limit exceeded