<html><head><meta name="color-scheme" content="light dark"></head><body><pre style="word-wrap: break-word; white-space: pre-wrap;">###########################
#    Match::Patent.pm     #
#      Version 1.01       #
#    (c) Ed Egan 2009     # 
###########################

package Patent;
no warnings 'redefine';
@ISA= qw (Common);
use strict;
use warnings;
use Match::PostalCodes;

sub new {
    my $class = shift;
    my $self = bless {}, $class;
    $self-&gt;{GLOBALS}-&gt;{ISO9660}=lc(shift);
    $self-&gt;{DIR}=shift;
    $self-&gt;{GLOBALS}-&gt;{SOURCEFILE}=$self-&gt;{GLOBALS}-&gt;{ISO9660}.".txt";
    $self-&gt;{GLOBALS}-&gt;{EXCEPTIONSFILE}=$self-&gt;{GLOBALS}-&gt;{ISO9660}."_exceptions.txt";
    $self-&gt;{GLOBALS}-&gt;{STOPWORDSFILE}="PatentLocations-Stopwords.txt";
    $self-&gt;{COUNT_MATCHES_LAST}=0;
    $self-&gt;{COUNT_MATCHES_TOTAL}=0;
    $self-&gt;{COUNT_EXPREAD}=0;
    $self-&gt;{COUNT_READ}=0;
    $self-&gt;Load($self-&gt;{DIR});
    $self-&gt;LoadStopWords;
    return $self;
}

sub Load {
    my $self=shift;
    my $Dir=shift;
    #The Load is robust to changes into the order of the columns and inclusion of new columns, but not to renamings
    my $sourcefile=$self-&gt;{GLOBALS}-&gt;{SOURCEFILE};
    my $sourcefilewithpath;
    if ($Dir) {$sourcefilewithpath="$Dir/$sourcefile";}
    else {$sourcefilewithpath=$sourcefile;}
    open (SOURCE,"$sourcefilewithpath") || die "Can not find the source file - Is it the module dir?".$!;
    undef my @header;
    my $headercol={};
    while (&lt;SOURCE&gt;) {
        chomp $_;
        if (!@header) {
            @header=split(/\t/,$_);
            for (my $i=0;$i&lt;=$#header;$i++) {$headercol-&gt;{$header[$i]}=$i;}
            next;
        }
        $self-&gt;{COUNT_READ}++;
        my @temp=split(/\t/,$_);
        if (!($temp[$headercol-&gt;{cty}])) {next;} #Must have a CTY field
        $self-&gt;{DATA}-&gt;{$temp[$headercol-&gt;{cty}]}-&gt;{CTY}=$temp[$headercol-&gt;{cty}];
        $self-&gt;{DATA}-&gt;{$temp[$headercol-&gt;{cty}]}-&gt;{RAWDATA}=\@temp;
    }
    close (SOURCE);
    $self-&gt;{COUNT_DATA}=scalar(keys(%{$self-&gt;{DATA}}));
    my $exceptionsfile=$self-&gt;{GLOBALS}-&gt;{EXCEPTIONSFILE};
    my $exceptionsfilewithpath;
    if ($Dir) {$exceptionsfilewithpath="$Dir/$exceptionsfile";}
    else {$exceptionsfilewithpath=$exceptionsfile;}
    if (-e $exceptionsfilewithpath) {
        open (EXCEPTIONS,"$exceptionsfilewithpath") || die "Can not find the exceptions file - Is it the module dir?".$!;
        undef @header;
        $headercol={};
        while (&lt;EXCEPTIONS&gt;) {
            chomp $_;
            if (!@header) {
                @header=split(/\t/,$_);
                for (my $i=0;$i&lt;=$#header;$i++) {$headercol-&gt;{$header[$i]}=$i;}
                next;
            }
            $self-&gt;{COUNT_EXPREAD}++;
            my @temp=split(/\t/,$_);
            if (!($temp[$headercol-&gt;{cty}])) {next;} #Must have a CTY field
            #$self-&gt;{DATA}-&gt;{$temp[$headercol-&gt;{cty}]}-&gt;{CTY}=$headercol-&gt;{cty};
            $self-&gt;{DATA}-&gt;{$temp[$headercol-&gt;{cty}]}-&gt;{EXP_DATA}=\@temp;
            $self-&gt;{DATA}-&gt;{$temp[$headercol-&gt;{cty}]}-&gt;{EXP_CITY}=$temp[$headercol-&gt;{city}];
            $self-&gt;{DATA}-&gt;{$temp[$headercol-&gt;{cty}]}-&gt;{EXP_ADM}=$temp[$headercol-&gt;{adm}];
            if (defined($headercol-&gt;{postcode})) {$self-&gt;{DATA}-&gt;{$temp[$headercol-&gt;{cty}]}-&gt;{EXP_POSTCODE}=$temp[$headercol-&gt;{postcode}];}
            else {$self-&gt;{DATA}-&gt;{$temp[$headercol-&gt;{cty}]}-&gt;{EXP_POSTCODE}="";}
            
        }
        close (EXCEPTIONS);
        $self-&gt;{EXCEPTIONSFILEEXISTS}=1;
    }
    return $self;
}

sub GetCount {
    my $self=shift;
    my $var=shift;
    $var="COUNT_".$var;
    if (defined($self-&gt;{$var})) {return $self-&gt;{$var};}
    else {return "ERROR";}
}

sub CleanAndParse {
    my $self=shift;
    $self-&gt;CleanFields;
    $self-&gt;Parse;
    return $self;
}

sub CleanFields {
    my $self=shift;
    foreach my $CTY (keys (%{$self-&gt;{DATA}})) {
        my @cleanlist=("EXP_CITY","EXP_ADM","EXP_POSTCODE");
        foreach my $unit (@cleanlist) {
            if (defined ($self-&gt;{DATA}-&gt;{$CTY}-&gt;{$unit})) {
                my $copy=$self-&gt;{DATA}-&gt;{$CTY}-&gt;{$unit};
                $copy=$self-&gt;CleanString($copy);
                if ($copy ne $self-&gt;{DATA}-&gt;{$CTY}-&gt;{$unit}) {$self-&gt;{DATA}-&gt;{$CTY}-&gt;{EXP_CLEANED}=1;}
                $self-&gt;{DATA}-&gt;{$CTY}-&gt;{$unit}=$copy;
            }
        }
        if (defined ($self-&gt;{DATA}-&gt;{$CTY}-&gt;{EXP_CITY}) || defined($self-&gt;{DATA}-&gt;{$CTY}-&gt;{EXP_ADM})) {
            undef my @temp;
            if (defined ($self-&gt;{DATA}-&gt;{$CTY}-&gt;{EXP_CITY})) {push (@temp,$self-&gt;{DATA}-&gt;{$CTY}-&gt;{EXP_CITY});}
            if (defined ($self-&gt;{DATA}-&gt;{$CTY}-&gt;{EXP_ADM})) {push (@temp,$self-&gt;{DATA}-&gt;{$CTY}-&gt;{EXP_ADM});}
            $self-&gt;{DATA}-&gt;{$CTY}-&gt;{EXP_LIST}=\@temp;
            $self-&gt;{DATA}-&gt;{$CTY}-&gt;{EXP_STR}=join("#",@{$self-&gt;{DATA}-&gt;{$CTY}-&gt;{EXP_LIST}});
        }
    }  
    return $self;
}

sub Parse {
    my $self=shift;
    my $PostcodeMethod=PostalCodes-&gt;new(uc($self-&gt;{GLOBALS}-&gt;{ISO9660}));
    foreach my $CTY (keys (%{$self-&gt;{DATA}})) {
        my $OrigCTY=$CTY;
        my $PostCode=undef;
        ($PostCode,$CTY)=$PostcodeMethod-&gt;ExtractPostalCode($CTY);
        if (defined ($PostCode)) {$self-&gt;{DATA}-&gt;{$OrigCTY}-&gt;{PRS_POSTCODE}=$PostCode;}
        $CTY=$self-&gt;ReplaceStopWords($CTY);
        if ($CTY=~/\,/) {
            $self-&gt;{DATA}-&gt;{$OrigCTY}-&gt;{CTY_COMMASEP}=1;
            my @temp=split(",",$CTY);
            undef my @cleanedtemp;
            foreach my $unit (@temp) {
                $unit=$self-&gt;CleanString($unit);
                if (defined($unit) &amp;&amp; $unit ne "") {push (@cleanedtemp,$unit);}
            }
            if (scalar(@cleanedtemp) &gt; 0) {
                $self-&gt;{DATA}-&gt;{$OrigCTY}-&gt;{CTY_LIST}=\@cleanedtemp;
                $self-&gt;{DATA}-&gt;{$OrigCTY}-&gt;{CTY_STR}=join("#",@{$self-&gt;{DATA}-&gt;{$OrigCTY}-&gt;{CTY_LIST}});
                $CTY=$self-&gt;{DATA}-&gt;{$OrigCTY}-&gt;{CTY_STR};
                $CTY=~s/#/ /g;
                $CTY=~s/^\s{1,}//; $CTY=~s/\s{1,}$//; $CTY=~s/\s{1,}/ /;
            }
            else {$CTY=$self-&gt;CleanString($CTY);}
        }
        else {$CTY=$self-&gt;CleanString($CTY);}
        $self-&gt;{DATA}-&gt;{$OrigCTY}-&gt;{CTY_CLEAN}=$CTY;
        if ($OrigCTY ne $CTY) {$self-&gt;{DATA}-&gt;{$OrigCTY}-&gt;{CTY_CLEANED}=1;}
    }
    return $self;
}

sub ReplaceStopWords {
    my $self=shift;
    my $str=shift;
    foreach my $stopword (keys (%{$self-&gt;{STOPWORDS}})) {
        if ($str=~/(^|\s|\W)$stopword(\s|\W|$)/) {$str=~s/(^|\s|\W)$stopword(\s|\W|$)/$1$self-&gt;{STOPWORDS}-&gt;{$stopword}$2/;}
    }
    $str=~s/(^|\s|\W)NEAR(\s|\W|$)/$1$2/; #For the moment throw out the NEAR marker
    $str=~s/\s{1,}/ /; $str=~s/^\s//; $str=~s/\s$//;
    return $str;
}

sub LoadStopWords {
    my $self=shift;
    my $stopfile=$self-&gt;{GLOBALS}-&gt;{STOPWORDSFILE};
    open (STOPWORDS,"$stopfile") || die "Can't open the Stopwords file to read".$!;
    while (&lt;STOPWORDS&gt;) {
        chomp $_;
        my ($key,$value)=split("\t",$_);
        $self-&gt;{STOPWORDS}-&gt;{$key}=$value;
    }
    close (STOPWORDS);
    return $self;    
}

sub GetUnMatched {
    my $self=shift;
    my $type=shift;
    $self-&gt;{COUNT_MATCHES_LAST}=0;
    my $UnMatched={};
    foreach my $CTY (keys (%{$self-&gt;{DATA}})) {
        if (defined $self-&gt;{DATA}-&gt;{$CTY}-&gt;{$type}) {
            if (!defined ($self-&gt;{DATA}-&gt;{$CTY}-&gt;{MATCHED})) {
                $UnMatched-&gt;{$CTY}=$self-&gt;{DATA}-&gt;{$CTY}-&gt;{$type};
            }
        }
    }
    return $UnMatched;
}

sub GetMatched {
    my $self=shift;
    my $Letter=shift;
    my $Matched={};
    foreach my $CTY (keys (%{$self-&gt;{DATA}})) {
        if (defined ($self-&gt;{DATA}-&gt;{$CTY}-&gt;{MATCHED})) {
            if (defined ($self-&gt;{DATA}-&gt;{$CTY}-&gt;{$Letter."LIST"})) {
                $Matched-&gt;{$CTY}=$self-&gt;{DATA}-&gt;{$CTY}-&gt;{$Letter."LIST"};
            }
        }
    }
    return $Matched;
}

sub FileCleanMatches {
    my $self=shift;
    my $Working=shift;
    foreach my $CTY (keys (%$Working)) {
        if (defined($Working-&gt;{$CTY}-&gt;{A_NAME})) {
            $self-&gt;{DATA}-&gt;{$CTY}-&gt;{A}=1;
            $self-&gt;{DATA}-&gt;{$CTY}-&gt;{A_NAME}=$Working-&gt;{$CTY}-&gt;{A_NAME};
            $self-&gt;{DATA}-&gt;{$CTY}-&gt;{A_UNI}=$Working-&gt;{$CTY}-&gt;{A_UNI};
            $self-&gt;{DATA}-&gt;{$CTY}-&gt;{A_LAT}=$Working-&gt;{$CTY}-&gt;{A_LAT};
            $self-&gt;{DATA}-&gt;{$CTY}-&gt;{A_LONG}=$Working-&gt;{$CTY}-&gt;{A_LONG};
        }
        if (defined($Working-&gt;{$CTY}-&gt;{P_NAME})) {
            $self-&gt;{DATA}-&gt;{$CTY}-&gt;{P}=1;
            $self-&gt;{DATA}-&gt;{$CTY}-&gt;{P_NAME}=$Working-&gt;{$CTY}-&gt;{P_NAME};
            $self-&gt;{DATA}-&gt;{$CTY}-&gt;{P_UNI}=$Working-&gt;{$CTY}-&gt;{P_UNI};
            $self-&gt;{DATA}-&gt;{$CTY}-&gt;{P_LAT}=$Working-&gt;{$CTY}-&gt;{P_LAT};
            $self-&gt;{DATA}-&gt;{$CTY}-&gt;{P_LONG}=$Working-&gt;{$CTY}-&gt;{P_LONG};
        }
    }
    return $self;
}

sub ReturnMatches {
    my $self=shift;
    my $Matched=shift;
    my $MatchType=shift;
    my $MatchCount=0;
    foreach my $CTY (keys (%$Matched)) {
        $self-&gt;{DATA}-&gt;{$CTY}-&gt;{MATCHED}=1;
        $self-&gt;{DATA}-&gt;{$CTY}-&gt;{MATCH_TYPE}=$MatchType;
        $MatchCount++;
        if (defined ($Matched-&gt;{$CTY}-&gt;{ALIST})) {$self-&gt;{DATA}-&gt;{$CTY}-&gt;{ALIST}=$Matched-&gt;{$CTY}-&gt;{ALIST};}
        if (defined ($Matched-&gt;{$CTY}-&gt;{PLIST})) {$self-&gt;{DATA}-&gt;{$CTY}-&gt;{PLIST}=$Matched-&gt;{$CTY}-&gt;{PLIST};}
    }
    $self-&gt;{COUNT_MATCHES_LAST}=$MatchCount;
    $self-&gt;ComputeTotalMatches;
    return $self;
}

sub ComputeTotalMatches {
    my $self=shift;
    my $count=0;
    foreach my $CTY (keys (%{$self-&gt;{DATA}})) {
        if (defined($self-&gt;{DATA}-&gt;{$CTY}-&gt;{MATCHED})) {$count++;}
    }
    $self-&gt;{COUNT_MATCHES_TOTAL}=$count;
    return $self;
}

sub ReturnData {
    my $self=shift;
    my $CTY=shift;
    my @Vars=("CTY","CTY_STR","EXP_CITY","EXP_ADM","EXP_POSTCODE","EXP_STR","PRS_POSTCODE","A_NAME","A_UNI","A_LAT","A_LONG","P_NAME","P_UNI","P_LAT","P_LONG","MATCH_TYPE");
    if (!$CTY) {return @Vars;} #Return the header
    undef my @Return;
    foreach my $Var (@Vars) {
        if (defined($self-&gt;{DATA}-&gt;{$CTY}-&gt;{$Var})) {
            push (@Return,$self-&gt;{DATA}-&gt;{$CTY}-&gt;{$Var});
        }
        else {push (@Return,"");}
    }
    return @Return;
}

sub ReturnKeys {
    my $self=shift;
    my $Type=shift;
    if (!$Type) {return (sort {$a cmp $b} (keys(%{$self-&gt;{DATA}})));}
    else {
        undef my @KeysUnsorted;
        foreach my $CTY (keys(%{$self-&gt;{DATA}})) {
            if (defined($self-&gt;{DATA}-&gt;{$CTY}-&gt;{$Type})) {push (@KeysUnsorted,$CTY);}
            elsif (defined($self-&gt;{DATA}-&gt;{$CTY}-&gt;{MATCH_TYPE})) {
                if ($self-&gt;{DATA}-&gt;{$CTY}-&gt;{MATCH_TYPE} eq $Type) {push (@KeysUnsorted,$CTY);}
            }
        }
        return (sort {$a cmp $b} (@KeysUnsorted));
    }
}

1;
</pre></body></html>