class TrieNode(object): ''' Contains the information of one node. It contains two lists of the positions where the string corresponding to that node is found. One stores only the positions of exact matches and the other all words that start with that string (match). Child maintenance is handled with a minimum list. A new TrieNode is given the maximum amount of children (number of acceptable characters). self.updateNode(value, exact): Adds the value to the value lists of that node. Exact-flag determines whether the value is added also to the list of exact matches. ''' def __init__(self, charMapSize, value = '', exact = False): """ Trie node contains two linked lists for its values: one is intended for exact matches (it is updated only with exact-flag raised). Upon creation, the minimum list type child list is created for that node. """ self.exact = LinkedList() self.match = LinkedList() if value: self.updateNode(value, exact) self.children = [None] * charMapSize def updateNode(self, position, exact): """ Add position info for this object """ self.match.addLast(position) if exact: self.exact.addLast(position)
class RedBlackNode(object): ''' Contains the information of one branch. The node knows its children (le[ft] and ri[ght]), its pa[rent], its color, its key and its val[ue]. It also knows if it's empty (end-of-list flag). Note that nodes cannot store empty values. Nodes know their family through the following methods methods: grandpa(): return the grandpa node or empty node sibling(): return the sibling node uncle(): return the uncle node or empty node updateNode(val): Add the val(ue) to this node ''' def __init__(self, str='', val=None, pa=None, red=True): """ The node can be empty upon creation (if val is not given) """ self.pa = pa self.le = None #left child self.ri = None #right child self.red = red self.key = str self.val = LinkedList() if val: self.empty = False self.updateNode(val) else: self.empty = True def __str__(self): """ String representation: return key as string """ return str(self.key) def __repr__(self): """ String representation: return key as string """ return str(self.key) def grandpa(self): """ Return the parent of a parent or empty node """ if not self.pa.empty: return self.pa.pa else: return RedBlackNode() def sibling(self): """ Return the sibling of the node (it must exist) """ if self == self.pa.le: return self.pa.ri else: return self.pa.le def uncle(self): """ Return the sibling of the parent or empty node """ grandpa = self.grandpa() if grandpa.empty: return RedBlackNode() elif grandpa.le == self.pa: return grandpa.ri else: return grandpa.le def updateNode(self, value): """ Add the value to this node """ self.val.addLast(value)
def _checkString(self): """ The searc term (which is a string) is searched for these things: - operator after another operator - operator first or last item in search term - words with zero letters after sanitation - badly placed parantheses - closed paranthesis must come after open paranthesis - equal number of open and closed parantheses The status property is set to 'ok' if search term is good or to 'bad' otherwise. Creates also a list telling how deep each paranthesis is in inner parantheses (in order to find a matching paranthesis). For example: 0 1 0 2 0 0 0 2 0 0 1 0 1 0 0 0 1 # pVal word ( word ( word AND word ) NOT word ) or ( word XOR word ) # words """ self._categorize(self.words) self._status = 'ok' # will be set to 'bad' if need be itemCount = len(self.types) paranthesisList = LinkedList() # queue for paranthesis self.pList = [0] * len(self.types) pVal = 0 for index, word in enumerate(self.words): if self.types[index] == 'W': # Words cannot be empty if self.sanitizer.sanitize(word) == '': self._status = 'bad' return if self.types[index] == 'P': # Words cannot be empty, even if they are 'partial' if self.sanitizer.sanitize(word) == '': self._status = 'bad' return # store paranthesis in a queue, it must be met by closing paranthesis if self.types[index] == '(': paranthesisList.addLast('(') pVal = pVal + 1 # pVal tells how deep we are in paranthesis self.pList[index] = pVal if self.types[index] == ')': self.pList[index] = pVal pVal = pVal - 1 # pVal tells how deep we are in paranthesis if paranthesisList.values(): # if we had open paranthesis paranthesisList.removeLast() # remove matching one from queue else: # we did not have matching paranthesis self._status = 'bad' # Search term is bad return # operation cannot be last term, first term or followed by another # operation if self.types[index] == 'O': if index > 0: if not self.types[index-1] == 'O': pass else: self._status = 'bad' return if index < itemCount - 1: if not self.types[index+1] == 'O': pass else: self._status = 'bad' return # We have traversed the words. If we have open paranthesis left, they # cannot have matching closed paranthesis, search term is bad if paranthesisList.values(): self._status = 'bad' return