"""Explicit weight-to-warehouse assignments; unassigned comparisons stay separate.""" from decimal import Decimal import re def allocations(text,codes,weight_pattern,to_kg): if len(codes)<2:return None code='('+'|'.join(re.escape(code) for code in sorted(codes,key=len,reverse=True))+r')(?![A-Za-z0-9])' forward=weight_pattern.pattern+r'\s*(?:货物)?\s*(?:发到|发往|送到|发|到|去)?\s*'+code reverse=code+r'\s*(?:[::]|分配|发|重)?\s*'+weight_pattern.pattern entries=[];used=[] for pattern,backwards in ((forward,False),(reverse,True)): for match in re.finditer(pattern,text,re.I): if any(match.start()start for start,end in used):continue values=match.groups() destination,value,unit=values if backwards else (values[2],values[0],values[1]) piece_weight=to_kg(value,unit) weight_start=match.start(2 if backwards else 1) carton=re.search(r'(第)?(\d+)\s*(?:箱|件)\s*(每(?:箱|件))?\s*$',text[:weight_start]) boxes=(1 if carton.group(1) else int(carton.group(2))) if carton else None pieces=([{'count':boxes,'weight':str(piece_weight),'dims':None,'dim_unit':'cm','position':weight_start}] if carton and (boxes==1 or carton.group(3)) else None) weight=piece_weight*boxes if pieces else piece_weight entries.append({'warehouse':destination.upper(),'weight':weight,'boxes':boxes,'packages':pieces}) used.append(match.span()) if len(entries)<2:return None totals={} for entry in entries: code=entry['warehouse'] if code not in totals: totals[code]=entry continue total=totals[code] total['weight']+=entry['weight'] total['boxes']=total['boxes']+entry['boxes'] if total['boxes'] is not None and entry['boxes'] is not None else None total['packages']=(total['packages']+entry['packages']) if total['packages'] and entry['packages'] else None return [{**entry,'weight':str(entry['weight'])} for entry in totals.values()]