示例#1
0
 def process_one_series(self, assumption, spec):
     provisional_total = 0
     totals = []
     seen_total_hint = False
     for pos in range(0, len(assumption), 1):
         if self.success: break
         if spec[pos] == spec.CRUFT:
             continue
         number = assumption[pos]
         if not seen_total_hint and number == 0 and number.info['category'] == 'Total':
             if assumption.zero_ok( pos, spec ):
                 seen_total_hint = True
                 spec[pos] = spec.GRAND_TOTAL
                 new_candidate = assumption.condense(spec)
                 spec.pop(pos)
                 self.candidates.append( new_candidate )
             continue
         if number != 0 and spec[pos] != spec.NON_TOTAL:
             #print 'pos/key: %s, number: %s, spec[pos]: %s' % (pos,number,spec[pos])
             if number == provisional_total:
                 if number.info['category'] == 'Total':
                     seen_total_hint = True
                 spec[pos] = spec.TOTAL
                 totals.append( provisional_total )
                 provisional_total = 0
                 number_of_totals = 0
                 for key in spec.keys():
                     if spec[key] == spec.TOTAL or spec[key] == spec.NON_TOTAL:
                         number_of_totals += 1
                 if number.info['category'] == 'Total' and number_of_totals == 1:
                     new_candidate = assumption.condense(spec)
                     self.candidates.append( new_candidate )
                 continue
             if sum(totals) and number == sum(totals) + provisional_total:
                 spec[pos] = spec.GRAND_TOTAL
                 #
                 # Aha!  Condense affected the spec.  Now _that_ is evil.
                 #
                 self.candidates.append( assumption.condense(spec) )
                 break
             #
             # XXX Untested
             if not seen_total_hint and number.info['category'] == 'Total':
                 seen_total_hint = True
                 nstr = str(number.str)
                 if len(nstr) % 2 == 0:
                     if nstr[len(nstr)/2:] == nstr[:len(nstr)/2]:
                         nstr = nstr[:len(nstr)/2]
                 self.fallback = ambiguousNumber( nstr, number.info.copy())
             if number.info['category'] == 'Total':
                 seen_total_hint = True
         provisional_total += number
示例#2
0
    def combine(self, start, end):
        ''' Combine a slice of numbers.
        
            Numbers are combined in reverse order, concatenating them
            as strings, then returning them as a single ambiguousNumber.
            An attempt to combine a string with an embedded negative
	    sign will return None.
        '''
        numlist = self.strs()[start:end]
        numlist.reverse()
        try:
            return ambiguousNumber( ''.join( numlist ), self.info.copy() )
        except ValueError:
            return None
示例#3
0
 def init_nums(self, nums):
     if isinstance(nums, ListType):
         return nums
     elif isinstance(nums, ambiguousNumber):
         return [nums]
     elif isinstance(nums, StringTypes):
         nums = nums.split()
         nums.reverse()
         l = []
         for num in nums:
             l.append( ambiguousNumber( num, self.info ) )
         return l
     else:
         raise ClusterArgumentError(('First','nums','<ambiguousCluster>, <ambiguousNumber> or <string>'))
示例#4
0
    def condense(self, oldspec):
        """ Return an unambiguous structured list of numbers
        
            Starting with an assumption, build a new list that does
            not contain cruft numbers, and consists of component numbers,
            totals, and a grand total.
            
            The starting assumption may take one of three forms.  It may
            end in a grand total of zero.  It may end in a bare total.
            or it may end in a grand total.  Each case is processed as
            required to produce the final structured list of numbers.
        """
        new = assumptionObject([])
        spec = copy(oldspec)
        aggressive_delete = True
        force_totals = False
        #
        # Compose a new list of numbers, containing no cruft, and
        # no trailers.
        append = False
        for pos in range(len(self) - 1, -1, -1):
            if spec[pos] == spec.CRUFT:
                continue
            if not append and spec[pos] == spec.NON_TOTAL:
                continue
            if spec[pos]:
                append = True
            if append:
                new.append(ambiguousNumber(self[pos].str, self[pos].info.copy()))
                if spec[pos]:
                    new[-1].update(state=spec[pos])
        new.reverse()
        #
        # We're not interested in zeros
        for pos in range(len(new) - 2, -1, -1):
            if new[pos] == 0:
                new.pop(pos)
        #
        # Just in case
        if new[-1] == 0:
            new[-1].update(state=spec.GRAND_TOTAL)
            for pos in range(len(new) - 2, -1, -1):
                new.pop(pos)
        #
        # Properly formed lists should be okay as they are.
        elif new[-1].state() == spec.GRAND_TOTAL:
            pass
        #
        # Normalize lists that include ordinary components in
        # the grand total.
        elif new[-1].state() == spec.TOTAL:
            new[-1].update(state=spec.GRAND_TOTAL)
            force_totals = True
            for pos in range(len(new) - 2, -1, -1):
                if new[pos].state():
                    force_totals = False
                if force_totals:
                    num = new[pos].str
                    info = new[pos].info.copy()
                    new.insert(pos + 1, ambiguousNumber(num, info))
                    new[pos + 1].update(state=spec.TOTAL)

        else:
            print new
            print "last value: %d, state of last value: %d" % (new[-1], new[-1].state())
            raise ThisCannotHappenException
        return new