Fallback characters

LTjake on 2003-05-21T18:13:03

When entering data into our (*sigh* test) cataloguing system, generally an from automated MARC record extraction (yay MARC::Record!), some of the data gets normalized.

By normalized, i mean it's all converted to one case, punctuations are removed, accented characters are changed to a-z letter (ex: é => e), etc. We've tried to comply mostly to the NACO normalization rules.

A basic character fallback hash can be found in POD::Escapes [Thanks TorgoX!] (see %Latin1Char_to_fallback), which i've modified slightly. Are there any modules that are explicitly for designed to do this type of normalization?

I'm sure this code sucks, but... :)

# LUT to convert diacritical and special characters
# Modified from Pod::Escapes

my (%Latin1Code_to_fallback, %Latin1Char_to_fallback);
%Latin1Code_to_fallback = ();

@Latin1Code_to_fallback{0xA0 .. 0xFF} = ( ' ', qq{!}, qq{C/}, 'PS', qq{\$?}, qq{Y=}, qq{|}, 'SS', qq{"}, ' ', 'a', qq{<<}, qq{!}, "", ' ', qq{-}, ' ', ' ', '2', '3', qq{'}, 'u', 'P', qq{*}, qq{,}, '1', 'o', qq{>>}, qq{1/4}, qq{1/2}, qq{3/4}, qq{?}, 'A', 'A', 'A', 'A', 'A', 'A', 'AE', 'C', 'E', 'E', 'E', 'E', 'I', 'I', 'I', 'I', 'D', 'N', 'O', 'O', 'O', 'O', 'O', 'x', 'O', 'U', 'U', 'U', 'U', 'U', 'Th', 'ss', 'a', 'a', 'a', 'a', 'a', 'a', 'ae', 'c', 'e', 'e', 'e', 'e', 'i', 'i', 'i', 'i', 'd', 'n', 'o', 'o', 'o', 'o', 'o', qq{/}, 'o', 'u', 'u', 'u', 'u', 'y', 'th', 'y', );

{
    %Latin1Char_to_fallback = ();
    my($k,$v);
    while( ($k,$v) = each %Latin1Code_to_fallback) {
        $Latin1Char_to_fallback{chr $k} = $v;
    }
}

# Massage data into a searchable value

sub normalize {
    my $data = shift;

    # Rules taken from NACO Normalization
    # http://lcweb.loc.gov/catdir/pcc/naco/normrule.html

    # Convert special chars to spaces
    $data =~ s/[\Q!(){}<>-;:.?,\/\\@*%=\$^~\E]/ /g;

    # Delete special chars
    $data =~ s/[\Q'[]|\E]//g;

    # Remove diacritical marks and convert special chars
    my @chars = split(//, $data);
    for my $i (0..$#chars) {
        $chars[$i] = $Latin1Char_to_fallback{$chars[$i]} if (ord($chars[$i]) >= 160 && ord($chars[$i]) <= 255);
    }
    $data = join('', @chars);

    # Convert lowercase to uppercase.
    $data =~ tr/a-z/A-Z/;

    # Remove leading and trailing spaces
    $data =~ s/^\s+|\s+$//g;

    # Condense multiple spaces
    $data =~ s/\s+/ /g;

    return $data;
}