File Coverage

blib/lib/MARC/Field/Normalize/NACO.pm
Criterion Covered Total %
statement 94 94 100.0
branch 18 34 52.9
condition 11 18 61.1
subroutine 19 19 100.0
pod n/a
total 142 165 86.0


line stmt bran cond sub pod time code
1             package MARC::Field::Normalize::NACO;
2              
3 1     1   19169 use strict;
  1         2  
  1         21  
4 1     1   3 use warnings;
  1         1  
  1         18  
5 1     1   2 use utf8;
  1         1  
  1         4  
6 1     1   604 use Unicode::Normalize qw(NFD);
  1         154394  
  1         113  
7 1     1   546 use List::MoreUtils qw(natatime);
  1         6729  
  1         5  
8 1     1   453 use MARC::Field;
  1         2  
  1         15  
9 1     1   519 use Method::Signatures;
  1         47144  
  1         5  
10              
11             our $VERSION = '0.05';
12              
13 1     1   386 use vars qw( @EXPORT_OK );
  1         2  
  1         43  
14 1     1   5 use Exporter 'import';
  1         1  
  1         48  
15             @EXPORT_OK = qw(
16             naco_from_string naco_from_array
17             naco_from_field naco_from_authority
18             );
19              
20 1 50 66 1   86895 func naco_from_string( Str $s, Bool :$keep_first_comma ) {
  44 50 66 44   1673  
  44 50 33     36  
  44 50       200  
  44 50       1930  
  44         45  
  44         269  
  44         58  
  44         65  
  44         52  
21             # decompose and uppercase
22 44         80 $s = uc( NFD($s) );
23              
24             # strip out combining diacritics
25 1     1   206 $s =~ s/\p{M}//g;
  1         1  
  1         12  
  44         5833  
26              
27             # transpose diagraphs and related characters
28 44         54 $s =~ s/Æ/AE/g;
29 44         40 $s =~ s/Å’/OE/g;
30 44         72 $s =~ s/Ø|Ò¨/O/g;
31 44         35 $s =~ s/Þ/TH/g;
32 44         38 $s =~ s/Ð/D/g;
33 44         27 $s =~ s/ß/SS/g;
34              
35             # transpose sub- and super-script with numerals
36 44         87 $s =~ tr/⁰¹²³⁴⁵⁶⁷⁸⁹/0123456789/;
37 44         56 $s =~ tr/₀₁₂₃₄₅₆₇₈₉/0123456789/;
38              
39             # delete or blank out punctuation
40 44         97 $s =~ s/[!"()\-{}<>;:.?¿¡\/\\*\|%=±⁺⁻™℗©°^_`~]/ /g;
41 44         70 $s =~ s/['\[\]ЪЬ·]//g;
42              
43             # blank out commas
44 44 100       50 if ($keep_first_comma) {
45 22         48 my $i = index $s, ',';
46 22         56 $s =~ s/,/ /g;
47 22         192 $s =~ s/^((?:.){$i})\s/$1,/;
48             # always strip off a trailing comma, even if it's the only one
49 22         40 $s =~ s/,$//;
50             }
51             else {
52 22         43 $s =~ s/,/ /g;
53             }
54              
55             # lastly, trim and deduplicate whitespace
56 44         78 $s =~ s/\s\s+/ /g;
57 44         123 $s =~ s/^\s+|\s+$//g;
58              
59 44         100 return $s;
60             }
61              
62 1 50 66 1   17327 func naco_from_array( ArrayRef $subfs ) {
  15 50   15   713  
  15 50       14  
  15         75  
  15         44  
63             # Expects $subfs == [ 'a', 'Thurber, James', 'd', '1914-', ... ]
64 15         79 my $itr = natatime 2, @$subfs;
65 15         15 my $out = '';
66 15         45 while (my ($subf, $val) = $itr->()) {
67 37         54 my $norm = naco_from_string( $val, keep_first_comma => $subf eq 'a' );
68 37         135 $out .= '$'. $subf . $norm;
69             }
70 15         87 return $out;
71             }
72              
73 1 50 66 1   3622 func naco_from_field( MARC::Field $f, :$subfields = 'a-df-hj-vx-z') {
  12 50   12   1851  
  12 50       12  
  12 50       74  
  12 50       193  
  12         21  
  12         13  
  12         23  
  12         14  
74 12         26 my @flat = map {@$_} grep {$_->[0] =~ /[$subfields]/} $f->subfields;
  27         39  
  45         289  
75 12         29 return naco_from_array( \@flat );
76             }
77              
78 1 50 66 1   1826 func naco_from_authority( MARC::Record $r ) {
  2 50   2   772  
  2 50       3  
  2         15  
  2         108  
79 2         6 return naco_from_field( scalar $r->field('1..'), subfields => 'a-z' );
80             }
81              
82             {
83 1     1   161 no warnings qw(once);
  1         1  
  1         74  
84             *MARC::Field::as_naco = \&naco_from_field;
85             }
86              
87             1;
88             __END__
89              
90             =encoding utf-8
91              
92             =head1 NAME
93              
94             MARC::Field::Normalize::NACO - Matching normalization for MARC::Field
95              
96             =head1 SYNOPSIS
97              
98             use MARC::Field;
99             use MARC::Field::Normalize::NACO;
100              
101             my $field = MARC::Field->new(
102             '100', ' ', ' ', a => 'Stephenson, Neal,', d => '1953-');
103             my $normalized = $field->as_naco;
104             my $custom = $field->as_naco(subfields => 'a');
105              
106             =head1 DESCRIPTION
107              
108             MARC::Field::Normalize::NACO turns MARC::Field objects into
109             strings canonicalized into NACO format. This makes them
110             suitable for matching against an index of similarly normalized
111             fields.
112              
113             The principal means of invoking is through the as_naco() method
114             that the module injects into MARC::Field when loaded. A string
115             is returned.
116              
117             This method takes an optional named parameter, subfields. The
118             value of this parameter should be something that fits nicely
119             into the regex qr/[$subfields]/, typically a range of letters.
120             The default value is "a-z68".
121              
122             =head1 AUTHOR
123              
124             Clay Fouts E<lt>cfouts@khephera.netE<gt>
125              
126             =head1 COPYRIGHT
127              
128             Copyright 2013 PTFS, Inc.
129              
130             =head1 LICENSE
131              
132             This library is free software; you can redistribute it and/or modify
133             it under the same terms as Perl itself.
134              
135             =head1 SEE ALSO
136              
137             =over
138              
139             =item *
140              
141             http://www.loc.gov/aba/pcc/naco/normrule-2.html
142              
143             =item *
144              
145             MARC::Record
146              
147             =back
148              
149             =cut