Ignore:
File:
1 edited

Legend:

Unmodified
Added
Removed
  • trunk/python/selector.py

    r2340 r2881  
    11import re
     2import math
     3import string
    24from asap._asap import selector as _selector, srctype
    35from asap.utils import unique, _to_list
     
    200202            raise TypeError('Unknown row number type. Use lists of integers.')
    201203
     204    def set_msselection_field(self, selection):
     205        """
     206        Set a field selection in msselection syntax. The msselection
     207        suppports the following syntax:
     208
     209        pattern match:
     210            - UNIX style pattern match for source name using '*'
     211              (compatible with set_name)
     212
     213        field id selection:
     214            - simple number in string ('0', '1', etc.)
     215            - range specification using '~' ('0~1', etc.)
     216            - range specification using '>' or '<' in combination
     217              with '=' ('>=1', '<3', etc.)
     218
     219        comma separated multiple selection:
     220            - selections can be combined by using ',' ('0,>1',
     221              'mysource*,2~4', etc.)
     222        """
     223        selection_list =  map(string.strip, selection.split(','))
     224        query_list = list(self.generate_query(selection_list))
     225        if len(query_list) > 0:
     226            original_query = self.get_query()
     227            if len(original_query) == 0 or re.match('.*(SRC|FIELD)NAME.*',original_query):
     228                query = 'SELECT FROM $1 WHERE ' + ' || '.join(query_list)
     229            else:
     230                query = 'SELECT FROM $1 WHERE (' + original_query + ') && (' + ' || '.join(query_list) + ')'
     231            self._settaql(query)
     232
     233    def generate_query(self, selection_list):
     234        for s in selection_list:
     235            if s.isdigit() or re.match('^[<>]=?[0-9]*$', s) or \
     236                    re.match('^[0-9]+~[0-9]+$', s):
     237                #print '"%s" is ID selection using < or <='%(s)
     238                a = FieldIdRegexGenerator(s)
     239                yield '(%s)'%(a.get_regex())
     240            elif len(s) > 0:
     241                #print '"%s" is UNIX style pattern match'%(s)
     242                yield '(SRCNAME == pattern(\'%s\'))'%(s)
     243       
    202244    def get_scans(self):
    203245        return list(self._getscans())
     
    275317                union.set_query(qs)
    276318        return union
     319
     320class FieldIdRegexGenerator(object):
     321    def __init__(self, pattern):
     322        if pattern.isdigit():
     323            self.regex = 'FIELDNAME == regex(\'.+__%s$\')'%(pattern)
     324        else:
     325            self.regex = None
     326            ineq = None
     327            if pattern.find('<') >= 0:
     328                ineq = '<'
     329                s = pattern.strip().lstrip(ineq).lstrip('=')
     330                if not s.isdigit():
     331                    raise RuntimeError('Invalid syntax: %s'%(pattern))
     332                self.id = int(s) + (-1 if pattern.find('=') < 0 else 0)
     333                self.template = string.Template('FIELDNAME == regex(\'.+__${reg}$\')')
     334            elif pattern.find('>') >= 0:
     335                ineq = '>'
     336                s = pattern.strip().lstrip(ineq).lstrip('=')
     337                if not s.isdigit():
     338                    raise RuntimeError('Invalid syntax: %s'%(pattern))
     339                self.id = int(s) + (-1 if pattern.find('=') >= 0 else 0)
     340                self.template = string.Template('FIELDNAME == regex(\'.+__[0-9]+$\') && FIELDNAME != regex(\'.+__${reg}$\')')
     341            elif pattern.find('~') >= 0:
     342                s = map(string.strip, pattern.split('~'))
     343                if len(s) == 2 and s[0].isdigit() and s[1].isdigit():
     344                    id0 = int(s[0])
     345                    id1 = int(s[1])
     346                    if id0 == 0:
     347                        self.id = id1
     348                        self.template = string.Template('FIELDNAME == regex(\'.+__${reg}$\')')
     349                    else:
     350                        self.id = [id0-1,id1]
     351                        self.template = string.Template('FIELDNAME == regex(\'.+__${reg}$\') && FIELDNAME != regex(\'.+__${optreg}$\')')
     352                else:
     353                    raise RuntimeError('Invalid syntax: %s'%(pattern))
     354            else:
     355                raise RuntimeError('Invalid syntax: %s'%(pattern))
     356            #print 'self.id=',self.id
     357
     358    def get_regex(self):
     359        if self.regex is not None:
     360            # 'X'
     361            return self.regex
     362        elif isinstance(self.id, list):
     363            # 'X~Y'
     364            return self.template.safe_substitute(reg=self.__compile(self.id[1]),
     365                                                 optreg=self.__compile(self.id[0]))
     366        else:
     367            # '<(=)X' or '>(=)X'
     368            return self.template.safe_substitute(reg=self.__compile(self.id))
     369
     370    def __compile(self, idx):
     371        pattern = ''
     372        if idx >= 0:
     373            numerics = map(int,list(str(idx)))
     374            #numerics.reverse()
     375            num_digits = len(numerics)
     376            #print 'numerics=',numerics
     377            if num_digits == 1:
     378                if numerics[0] == 0:
     379                    pattern = '0'
     380                else:
     381                    pattern = '[0-%s]'%(numerics[0])
     382            elif num_digits == 2:
     383                pattern = '(%s)'%('|'.join(
     384                        list(self.__gen_two_digit_pattern(numerics))))
     385            elif num_digits == 3:
     386                pattern = '(%s)'%('|'.join(
     387                        list(self.__gen_three_digit_pattern(numerics))))
     388            else:
     389                raise RuntimeError('ID > 999 is not supported')
     390        else:
     391            raise RuntimeError('ID must be >= 0')
     392        return pattern
     393
     394    def __gen_two_digit_pattern(self, numerics):
     395        assert len(numerics) == 2
     396        yield '[0-9]'
     397        if numerics[0] == 2:
     398            yield '1[0-9]'
     399        elif numerics[0] > 2:
     400            yield '[1-%s][0-9]'%(numerics[0]-1)
     401        if numerics[1] == 0:
     402            yield '%s%s'%(numerics[0],numerics[1])
     403        else:
     404            yield '%s[0-%s]'%(numerics[0],numerics[1])
     405
     406    def __gen_three_digit_pattern(self, numerics):
     407        assert len(numerics) == 3
     408        yield '[0-9]'
     409        yield '[1-9][0-9]'
     410        if numerics[0] == 2:
     411            yield '1[0-9][0-9]'
     412        elif numerics[0] > 2:
     413            yield '[1-%s][0-9][0-9]'%(numerics[0]-1)
     414        if numerics[1] == 0:
     415            if numerics[2] == 0:
     416                yield '%s00'%(numerics[0])
     417            else:
     418                yield '%s0[0-%s]'%(numerics[0],numerics[2])
     419        else:
     420            if numerics[1] > 1:
     421                yield '%s[0-%s][0-9]'%(numerics[0],numerics[1]-1)
     422            elif numerics[1] == 1:
     423                yield '%s0[0-9]'%(numerics[0])
     424            if numerics[0] == 0:
     425                yield '%s%s%s'%(numerics[0],numerics[1],numerics[2])
     426            else:
     427                yield '%s%s[0-%s]'%(numerics[0],numerics[1],numerics[2])
Note: See TracChangeset for help on using the changeset viewer.