{ my @ruleset; sub define_rules { my $rules = shift; for my $rp ( split /\n\n/, $rules ) { my @rules = grep !/^#/, split /\n/, $rp; s/#.*// for @rules; s/^\s+// for @rules; s/\s+$// for @rules; my $fam_pat = shift @rules; my %rules = map { my( $when ) = $_->[0] =~ /(.*):/; # will be undef if no colon defined $when or $when = ''; ( $when => $_->[1] ) } map { /(.*)\bkey\s*=\s*(.*)/ ? [ $1, $2 ] : () } @rules; push @ruleset, [ $fam_pat, \%rules, ]; } } # $key = get_key_by_rules( $family, $family_release ); # if it matches a rule but the rule doesn't specify a key to return, # this function returns its first argument (i.e. $family). # if no match occurs, it returns undef; but your ruleset should # probably have a catch-all condition at the end so this never happens. sub get_key_by_rules { my( $major, $minor ) = @_; defined $minor or $minor = ''; for my $ruleset ( @ruleset ) { my( $maj_pat, $rules_hr, $default ) = @$ruleset; if ( $major =~ /$maj_pat/ ) { if ( exists $rules_hr->{$minor} ) { my $ret = $rules_hr->{$minor}; return $ret gt '' ? $ret : $major; } elsif ( exists $rules_hr->{''} ) { my $ret = $rules_hr->{''}; return $ret gt '' ? $ret : $major; } else { return(); } } } return(); } } #### define_rules( <<'EOF' ); # careful - all whitespace is significant in this format. # use whole-line comments if you need spacers. UNIGRAPHICS_NX 1: key = NX1 2: key = NX2 key = other \bNX\b 3: key = NX3 4: key = NX4 SOLID_EDGE 18: key = SE18 16: key = SE16 17: key = SE17 key = other WEBTOOLS key = # use the default key, which is $family TC_ENGR-IMAN key = TC_ENG TC_COMMUNITY key = TC_COM # default. Unfortunately, this "comment" isn't optional. :-( key = other EOF #### $family = trim($family); ( undef, $family_release ) = $family_release =~ /(P|V)(\d+)*/; #print "$family\n"; my $key = get_key_by_rules( $family, $family_release ); $people{$user}{$key}++; $people{$user}{TOTAL}++;