~ubuntu-branches/ubuntu/natty/moin/natty-updates

« back to all changes in this revision

Viewing changes to MoinMoin/search/Xapian/tokenizer.py

  • Committer: Bazaar Package Importer
  • Author(s): Jonas Smedegaard
  • Date: 2008-06-22 21:17:13 UTC
  • mto: This revision was merged to the branch mainline in revision 18.
  • Revision ID: james.westby@ubuntu.com-20080622211713-inlv5k4eifxckelr
ImportĀ upstreamĀ versionĀ 1.7.0

Show diffs side-by-side

added added

removed removed

Lines of Context:
1
 
# -*- coding: iso-8859-1 -*-
2
 
"""
3
 
    MoinMoin - A text analyzer for wiki syntax
4
 
 
5
 
    @copyright: 2006-2008 MoinMoin:ThomasWaldmann,
6
 
                2006 MoinMoin:FranzPletz
7
 
    @license: GNU GPL, see COPYING for details.
8
 
"""
9
 
 
10
 
import re
11
 
import xapian
12
 
 
13
 
from MoinMoin.parser.text_moin_wiki import Parser as WikiParser
14
 
from MoinMoin import config
15
 
 
16
 
 
17
 
class WikiAnalyzer(object):
18
 
    """ A text analyzer for wiki syntax
19
 
 
20
 
    The purpose of this class is to analyze texts/pages in wiki syntax
21
 
    and yield single terms to feed into the xapian database.
22
 
    """
23
 
 
24
 
    singleword = r"[%(u)s][%(l)s]+" % {
25
 
                     'u': config.chars_upper,
26
 
                     'l': config.chars_lower,
27
 
                 }
28
 
 
29
 
    singleword_re = re.compile(singleword, re.U)
30
 
    wikiword_re = re.compile(WikiParser.word_rule, re.UNICODE|re.VERBOSE)
31
 
 
32
 
    token_re = re.compile(
33
 
        r"(?P<company>\w+[&@]\w+)|" + # company names like AT&T and Excite@Home.
34
 
        r"(?P<email>\w+([.-]\w+)*@\w+([.-]\w+)*)|" +    # email addresses
35
 
        r"(?P<acronym>(\w\.)+)|" +          # acronyms: U.S.A., I.B.M., etc.
36
 
        r"(?P<word>\w+)",                   # words (including WikiWords)
37
 
        re.U)
38
 
 
39
 
    dot_re = re.compile(r"[-_/,.]")
40
 
    mail_re = re.compile(r"[-_/,.]|(@)")
41
 
    alpha_num_re = re.compile(r"\d+|\D+")
42
 
 
43
 
    def __init__(self, request=None, language=None):
44
 
        """
45
 
        @param request: current request
46
 
        @param language: if given, the language in which to stem words
47
 
        """
48
 
        self.stemmer = None
49
 
        if request and request.cfg.xapian_stemming and language:
50
 
            try:
51
 
                stemmer = xapian.Stem(language)
52
 
                # we need this wrapper because the stemmer returns a utf-8
53
 
                # encoded string even when it gets fed with unicode objects:
54
 
                self.stemmer = lambda word: stemmer(word).decode('utf-8')
55
 
            except xapian.InvalidArgumentError:
56
 
                # lang is not stemmable or not available
57
 
                pass
58
 
 
59
 
    def raw_tokenize_word(self, word, pos):
60
 
        """ try to further tokenize some word starting at pos """
61
 
        yield (word, pos)
62
 
        if self.wikiword_re.match(word):
63
 
            # if it is a CamelCaseWord, we additionally try to tokenize Camel, Case and Word
64
 
            for m in re.finditer(self.singleword_re, word):
65
 
                mw, mp = m.group(), pos + m.start()
66
 
                for w, p in self.raw_tokenize_word(mw, mp):
67
 
                    yield (w, p)
68
 
        else:
69
 
            # if we have Foo42, yield Foo and 42
70
 
            for m in re.finditer(self.alpha_num_re, word):
71
 
                mw, mp = m.group(), pos + m.start()
72
 
                if mw != word:
73
 
                    for w, p in self.raw_tokenize_word(mw, mp):
74
 
                        yield (w, p)
75
 
 
76
 
    def raw_tokenize(self, value):
77
 
        """ Yield a stream of words from a string.
78
 
 
79
 
        @param value: string to split, must be an unicode object or a list of
80
 
                      unicode objects
81
 
        """
82
 
        if isinstance(value, list): # used for page links
83
 
            for v in value:
84
 
                yield (v, 0)
85
 
        else:
86
 
            tokenstream = re.finditer(self.token_re, value)
87
 
            for m in tokenstream:
88
 
                if m.group("acronym"):
89
 
                    yield (m.group("acronym").replace('.', ''), m.start())
90
 
                elif m.group("company"):
91
 
                    yield (m.group("company"), m.start())
92
 
                elif m.group("email"):
93
 
                    displ = 0
94
 
                    for word in self.mail_re.split(m.group("email")):
95
 
                        if word:
96
 
                            yield (word, m.start() + displ)
97
 
                            displ += len(word) + 1
98
 
                elif m.group("word"):
99
 
                    for word, pos in self.raw_tokenize_word(m.group("word"), m.start()):
100
 
                        yield word, pos
101
 
 
102
 
    def tokenize(self, value):
103
 
        """
104
 
        Yield a stream of raw lower cased and stemmed words from a string.
105
 
 
106
 
        @param value: string to split, must be an unicode object or a list of
107
 
                      unicode objects
108
 
        """
109
 
        if self.stemmer:
110
 
 
111
 
            def stemmer(value):
112
 
                stemmed = self.stemmer(value)
113
 
                if stemmed != value:
114
 
                    return stemmed
115
 
                else:
116
 
                    return ''
117
 
        else:
118
 
            stemmer = lambda v: ''
119
 
 
120
 
        for word, pos in self.raw_tokenize(value):
121
 
            # Xapian stemmer expects lowercase input
122
 
            word = word.lower()
123
 
            yield word, stemmer(word)
124