File Coverage

blib/lib/Biblio/Citation/Parser/Jiao.pm
Criterion Covered Total %
statement 278 719 38.6
branch 94 356 26.4
condition 20 98 20.4
subroutine 27 38 71.0
pod 2 33 6.0
total 421 1244 33.8


line stmt bran cond sub pod time code
1             package Biblio::Citation::Parser::Jiao;
2              
3             ######################################################################
4             #
5             # Biblio::Citation::Parser::Jiao;
6             #
7             ######################################################################
8             #
9             # This file is part of ParaCite Tools (http://paracite.eprints.org/developers/)
10             # Based on Zhuoan Jiao's (zj@ecs.soton.ac.uk) citation parser (available
11             # at http://arabica.ecs.soton.ac.uk/code/doc/ReadMe.html)
12             #
13             # The code is relatively unchanged, except to bring into compliance
14             # with the ParaCite metadata style, and to allow interoperability with
15             # the other parsers.
16             #
17             # Copyright (c) 2004 University of Southampton, UK. SO17 1BJ.
18             #
19             # ParaTools is free software; you can redistribute it and/or modify
20             # it under the terms of the GNU General Public License as published by
21             # the Free Software Foundation; either version 2 of the License, or
22             # (at your option) any later version.
23             #
24             # ParaTools is distributed in the hope that it will be useful,
25             # but WITHOUT ANY WARRANTY; without even the implied warranty of
26             # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
27             # GNU General Public License for more details.
28             #
29             # You should have received a copy of the GNU General Public License
30             # along with ParaTools; if not, write to the Free Software
31             # Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
32             #
33             ######################################################################
34              
35 1     1   1065 use strict;
  1         2  
  1         35  
36 1     1   4 use vars qw(@ISA @EXPORT @EXPORT_OK);
  1         2  
  1         54  
37             # This provides various utility functions.
38 1     1   699 use Biblio::Citation::Parser::Jiao::Utility;
  1         2  
  1         145  
39 1     1   5 use Biblio::Citation::Parser::Utils;
  1         1  
  1         26545  
40              
41             require Exporter;
42             @ISA = ("Exporter", "Biblio::Citation::Parser");
43             our @EXPORT_OK = ( 'parse', 'new' );
44              
45              
46             =pod
47              
48             =head1 NAME
49              
50             B - citation parsing using Zhuoan Jiao's
51             parsing module.
52              
53              
54             =head1 SYNOPSIS
55              
56             use Biblio::Citation::Parser::Jiao;
57             # Parse a simple reference
58             $parser = new Biblio::Citation::Parser::Jiao;
59             $metadata = $parser->parse("M. Jewell (2002) Citation Parsing for Beginners. Journal of Madeup References 4(3).");
60             print "The title of this article is ".$metadata->{atitle}."\n";
61              
62             =head1 DESCRIPTION
63              
64             Biblio::Citation::Parser::Jiao uses a reference parsing module written by
65             Zhuoan Jiao (zj@ecs.soton.ac.uk). This is a good module to use if titles are not required (if they are in double-quotes they will be picked up, however).
66              
67             For more information see:
68             http://arabica.ecs.soton.ac.uk/code/doc/ref/Parser/about_Citation_module.html
69              
70             The module has been repackaged to comply with the ParaCite metadata style
71             and uses the Citation parser interface to preserve interoperability with the other
72             modules.
73              
74             =head1 METHODS
75              
76             =over 4
77              
78             =item $parser = Biblio::Citation::Parser::Jiao-Enew()
79              
80             The new() method creates a new parser.
81              
82             =cut
83              
84             sub new {
85 1     1 1 70 my $class = shift;
86 1         2 my $cite = {};
87 1         5 bless $cite, $class;
88             }
89              
90             =pod
91              
92             =item $metadata = $parser-Eparse($reference, [$notrim]);
93              
94             This method provides a wrapper to the functions within the Jiao module that carry out the parsing. Simply pass a reference string, and a metadata hash is returned. Note that this is trimmed to comply to OpenURL standards (thus removing some information that you may wish to keep). To prevent this from occurring, ensure that $notrim is non-zero.
95              
96             =cut
97              
98             sub parse
99             {
100 1     1 1 7 my($self, $ref, $notrim) = @_;
101 1         2 my $cite = {};
102 1         4 bless $cite, "Biblio::Citation::Parser::Jiao";
103 1         5 $cite->initialize($ref);
104 1         4 $cite->{auinit} = $cite->{aufirst};
105 1         4 $cite->{date} = $cite->{year};
106 1         4 $cite = _debless($cite);
107 1 50       25 my $metadata = ($notrim ? $cite : trim_openurl($cite));
108            
109 1         11 return $metadata;
110             }
111              
112             sub _debless
113             {
114 1     1   3 my($hash) = @_;
115 1         2 my $out = {};
116 1         8 foreach(keys %$hash)
117             {
118 20         48 $out->{$_} = $hash->{$_};
119             }
120 1         5 return $out;
121             }
122              
123             sub initialize {
124 1     1 0 2 my $cite = shift;
125 1   50     4 my $text = shift || return;
126 1         11 $cite->{'text'} = $text;
127 1         3 $cite->{'rest_text'} = $cite->{'text'};
128            
129 1         3 $cite->{'aufull'} = '';
130 1         3 $cite->{'aulast'} = '';
131 1         2 $cite->{'aufirst'}= '';
132 1         3 $cite->{'authors'}= '';
133 1         3 $cite->{'atitle'} = '';
134 1         3 $cite->{'title'} = '';
135 1         2 $cite->{'volume'} = '';
136 1         3 $cite->{'issue'} = '';
137 1         2 $cite->{'supl'} = '';
138 1         2 $cite->{'spage'} = '';
139 1         4 $cite->{'year'} = '';
140 1         2 $cite->{'targetURL'} = '';
141              
142 1         2 $cite->{'featureID'} = '';
143 1         3 $cite->{'jnl_spos'} = 0;
144 1         3 $cite->{'jnl_epos'} = 0;
145 1         2 $cite->{'num_of_fig'}= 0;
146              
147 1         10 $cite->find_metadata();
148 1         6 $cite->find_featureID();
149             }
150              
151             #
152             # Actions
153             #
154             sub pre_process {
155 1     1 0 2 my $cite = shift;
156 1         2 my $Text = $cite->{'text'};
157              
158 1         6 $Text = normalisation($Text);
159 1         6 $Text = normalise_date($Text);
160 1         5 $Text = normalise_html($Text);
161             # remove front label to get accurate $nFig
162             # (Note: do not perform this for arXiv ref. like: "46(4), 90 (1993)")
163             # [Smith, 1998], [1], (1), (1a) ...
164 1         4 $Text =~ s/^\s*[\[(]\s* # bracket
165             ([^\])]+?)\s* # content
166             [\])]\s*//x; # bracket
167              
168             # "1. Gary Smith, ...."
169 1         5 $Text =~ s/^\d+\s*\.\s+//;
170             # "1 Gary Smith, ...."
171 1         3 $Text =~ s/^\s*\d+ ([A-Z])/$1/;
172             # "2) Brand, P. ..."
173 1         4 $Text =~ s/^[\[\(]?\s*\w+\s*[\])]\s*//;
174            
175 1         3 $cite->{'rest_text'} = $Text;
176              
177 1         4 my $nFig = num_of_figures($Text);
178 1         3 $cite->{'num_of_fig'} = $nFig;
179             }
180              
181             sub find_metadata {
182 1     1 0 2 my $cite = shift;
183              
184 1 50       5 return 0 if (!defined($cite->{'text'}));
185 1         7 $cite->pre_process();
186              
187             # find URL
188 1         5 $cite->find_url();
189              
190 1         2 my $nFig = $cite->{'num_of_fig'};
191              
192             # find the authors
193 1 50       6 if ($cite->find_authors()) {
194 1         5 $cite->find_first_author()
195             };
196              
197             # find article titile
198 1         5 $cite->find_atitle();
199              
200             # only process references to 'journal' articles.
201 1 50       4 return 0 if ($nFig == 0) ; # no number, ignore.
202 1 50       6 return 0 if ($nFig >= 8); # too many numbers, maybe an error, ignore.
203             # return 0 if ($cite->{'rest_text'} =~ /\W(proc.|proceedings) of /i);
204              
205             # extract 'supplement' first before find_vol_no_pg_year()
206 1         5 $cite->find_supplement();
207              
208 1 50 33     5 if ($cite->find_vol_no_pg_year() or
209             $cite->find_vol_pg_year()) {
210            
211 1         5 $cite->find_jnl_name();
212 1         2 return 1
213             };
214              
215 0 0       0 if ($cite->guess_vol_no_pg()) {
216 0         0 $cite->find_jnl_name();
217 0         0 return 1;
218             };
219              
220 0 0 0     0 if ($cite->find_vol_no() or
221             $cite->find_vol_supl()) {
222            
223 0         0 $cite->find_jnl_name();
224 0         0 $cite->find_page();
225 0         0 $cite->find_year();
226            
227 0         0 return 1;
228             };
229              
230 0 0       0 if ($cite->guess_vol_pg()) {
231 0         0 $cite->find_year();
232 0         0 $cite->find_jnl_name();
233            
234 0         0 return 1;
235             };
236            
237 0 0       0 if ($cite->guess_vol_year()) {
238              
239 0         0 $cite->find_page();
240 0         0 $cite->find_jnl_name();
241            
242 0         0 return 1;
243             };
244              
245 0         0 my $Count = 0;
246 0 0       0 $Count++ if ($cite->find_vol());
247 0 0       0 $Count++ if ($cite->find_issue());
248 0 0       0 $Count++ if ($cite->find_supplement());
249 0 0       0 $Count++ if ($cite->find_jnl_name());
250 0 0       0 $Count++ if ($cite->find_page());
251 0 0       0 $Count++ if ($cite->find_year());
252            
253 0 0       0 return 1 if ($Count >=2 );
254            
255             # too few metadata
256 0         0 return 0
257             }
258              
259             sub find_atitle {
260 1     1 0 3 my $cite = shift;
261 1         4 my $Text = $cite->{'rest_text'};
262            
263             # title is quoted.
264             # return 0 if ($Text !~ /(['"])/); #
265             # my $Qt = $1;
266             # ignore ' case, because author nams may contain ', e.g.
267             # A. I. L'vov, V. A. Petrun'kin, and M. Schumacher,
268             # Phys. Rev. C 55, 359 (1997)
269 1 50       5 return 0 if ($Text !~ /"/);
270              
271 0 0 0     0 if ($Text =~ /"(.+?)"\s*\.?/ and
272             word_count($1) >= 2) {
273 0         0 my $Guess_title = $1;
274 0 0       0 return 0 if ($Guess_title =~ /^http:/i);
275            
276 0         0 $cite->{'atitle'} = $Guess_title;
277             # use ';' !
278             # $Text =~ s/$Qt(.+?)$Qt\s*\.?/;/o;
279             # $Text =~ s/"[^"]+"\s*\.?/;/;
280 0         0 $Text =~ s/"[^"]+"/" "/;
281             # $Text =~ s/[,;.]\s*[,;.]/,/g; # doesn't work
282 0         0 while ($Text =~ /[,;.]\s*[,;.]/g) {
283 0         0 $Text =~ s/[,;.]\s*[,;.]/,/
284             };
285 0         0 $Text =~ s/^[;" ]+//;
286 0         0 $cite->{'rest_text'} = $Text;
287 0         0 return 1
288             };
289              
290 0         0 return 0
291             }
292              
293             # for the OpCit Project .
294             sub find_featureID {
295 1     1 0 2 my $cite = shift;
296              
297 1         3 my $featureID = '';
298 1 50       6 $featureID .= "v$cite->{'volume'}" if ($cite->{'volume'});
299 1 50       5 $featureID .= ":n$cite->{'issue'}" if ($cite->{'issue'});
300 1 50       4 $featureID .= ":s$cite->{'supl'}" if ($cite->{'supl'});
301 1 50       6 $featureID .= ":p$cite->{'spage'}" if ($cite->{'spage'});
302 1 50       6 $featureID .= ":y$cite->{'year'}" if ($cite->{'year'});
303              
304             # tidy up
305             # $featureID =~ s/:[nsp]\s*:/:/g; # doesn't work.
306 1         9 while ($featureID =~ /:[nsp]\s*:/g) {
307 0         0 $featureID =~ s/:[nsp]\s*:/:/
308             };
309 1         2 $featureID =~ s/^://;
310 1         3 $featureID =~ s/\s+//g;
311              
312 1         6 my @Features = split(':', $featureID);
313              
314             # ignore those having too few metadata
315 1 50       5 if (scalar(@Features) >= 2) {
316             # standardize
317 1         3 $featureID = lc($featureID);
318 1         4 $cite->{'featureID'} = $featureID;
319             };
320             }
321              
322              
323             sub find_authors {
324 1     1 0 2 my $cite = shift;
325 1         3 my $Text = $cite->{'rest_text'};
326            
327 1         5 my $aText = locate_authors($Text);
328 1 50 33     14 return 0 if ($aText eq '' or $aText =~ /^\W+$/);
329            
330 1         3 my @Chunks = ();
331 1         6 @Chunks = split(/\s*[,;:]\s*/, $aText);
332            
333             # ignore text longer than 4 words (don't count initials)
334 1 50 33     6 return 0 if (word_count($Chunks[0])>4 and no_initials($Chunks[0]));
335            
336 1         3 my($author, $Authors) = ('','');
337 1         3 while (@Chunks) {
338 1 50       5 if (scalar(@Chunks)==1) {
339 0 0       0 last if !full_name($Chunks[0]);
340 0         0 $author = normalise_name($Chunks[0]);
341 0         0 $Authors = "$Authors:$author";
342             last
343 0         0 };
344            
345              
346             # (1) forename and surname are not separated by [,;].
347 1 50       5 if (full_name($Chunks[0])){
    50          
348 0 0       0 if ($Chunks[1] =~ /^\s*Jr\.?\s*$/i) {
    0          
349 0         0 $author = "$Chunks[0], $Chunks[1]";
350 0         0 $author = normalise_name($author);
351 0         0 $Authors = "$Authors:$author";
352 0         0 splice(@Chunks, 0, 2); # remove the first two
353             next
354 0         0 }
355             elsif (!only_initials($Chunks[1])) {
356 0         0 $author = normalise_name($Chunks[0]);
357 0         0 $Authors = "$Authors:$author";
358 0         0 shift(@Chunks);
359             next
360 0         0 }
361             }
362             elsif (full_name($Chunks[1])) {
363             # $Chunks[0] is not a name, skip.
364 0         0 shift @Chunks;
365             next
366 0         0 };
367              
368             # (2) forename and surname are separated by [,;].
369             # Ignore text containing too many words.
370 1         4 my $aFull = "$Chunks[0] $Chunks[1]";
371 1         2 my @abbr = ();
372 1 50       3 last if (word_count($aFull) > 4);
373 1 50       5 last if ($aFull =~ /[\d\/]+/);
374            
375             # journal title maybe mixed up with the name
376 1 50 33     7 last if (@abbr = ($aFull =~ /\w\w\./g) and (@abbr >= 2));
377              
378             # surname first.
379             # "Oemler, A., Jr. and Lynds, C. R. 1975, ApJ, 199, 558"
380 1 50       4 if (scalar(@Chunks) > 2) {
381 0 0 0     0 if (is_surname($Chunks[0]) and
      0        
382             has_initials($Chunks[1]) and
383             $Chunks[2] =~ /^\s*Jr\.?\s*$/i) {
384 0         0 $author = "$Chunks[1] $Chunks[0], Jr";
385 0         0 $author = normalise_name($author);
386 0         0 $Authors = "$Authors:$author";
387 0         0 splice(@Chunks, 0, 3); # remove the first three
388             next
389 0         0 };
390             };
391              
392             # surname first
393             # "Reisenegger, A. and Miralda-Escude, J. 1995, ApJ, 449, 476
394 1 50 33     5 if (is_surname($Chunks[0]) and
395             has_initials($Chunks[1])) {
396 1 50       3 if ($Chunks[1] =~ /(.+?\.?)\s*Jr\.?\s*$/i){
397 0         0 $author = "$1 $Chunks[0], Jr";
398             }
399             else
400             {
401 1         4 $author = "$Chunks[1] $Chunks[0]";
402             };
403 1         6 $author = normalise_name($author);
404 1         4 $Authors = "$Authors:$author";
405 1         3 splice(@Chunks, 0, 2); # remove the first two
406             next
407 1         5 };
408            
409             # forename first
410 0 0 0     0 if (only_initials($Chunks[0]) and
411             is_surname($Chunks[1])) {
412 0 0       0 if ($Chunks[0] =~ /(.+?[. ])\s*Jr\.?\s*$/i){
413 0         0 $author = "$1 $Chunks[1], Jr";
414             }
415             else
416             {
417 0         0 $author = $aFull
418             };
419 0         0 $author = normalise_name($author);
420 0         0 $Authors = "$Authors:$author";
421 0         0 splice(@Chunks, 0, 2); # remove the first two
422             next
423 0         0 };
424            
425             # 'Liu, Gong', hard to tell which is the surname;
426 0 0 0     0 if (no_initials($Chunks[0]) and
427             no_initials($Chunks[1])) {
428 0 0       0 if (word_count($aFull) <= 4 ) {
429 0         0 $author = normalise_name($aFull);
430 0         0 $Authors = "$Authors:$author";
431 0         0 splice(@Chunks, 0, 2); # remove the first two
432             next
433 0         0 }
434             };
435            
436             # cannot determin the author name
437             last
438            
439 0         0 }; # end of while
440            
441 1 50       5 return 0 if ($Authors eq '');
442 1         5 $Authors =~ s/^://;
443 1         6 $cite->{'authors'} = $Authors;
444             }
445              
446             sub find_first_author {
447 1     1 0 2 my $cite = shift;
448            
449 1 50       5 return 0 if ($cite->{'authors'} eq '');
450              
451 1         4 my @Authors = split(':', $cite->{'authors'});
452 1         3 $cite->{'aufull'} = shift @Authors;
453 1 50       7 if ($cite->{'aufull'} =~ /./)
454             {
455 1         8 ($cite->{'aufirst'}, $cite->{'aulast'}) = ($cite->{'aufull'} =~ /^(.+)\.(.+)$/);
456             }
457             else
458             {
459 0         0 ($cite->{'aufirst'}, $cite->{'aulast'}) = ($cite->{'aufull'} =~ /^(.+)\s+(.+)$/);
460             }
461              
462             }
463              
464              
465             # locate_authors
466             sub locate_authors {
467 1     1 0 2 my $Text = shift;
468              
469 1         3 $Text =~ s/^\s*For .*?review(s)?\W+//i;
470 1         3 $Text =~ s/^\s*(see )?also //i;
471 1         4 $Text =~ s/^\s*see[, ]\s*for example\W+//i;
472 1         3 $Text =~ s/^\s*see e\.g\.\W+//i;
473 1         3 my $aText = $Text;
474              
475             # author name(s) is assumed to be in front of a consecutive
476             # 4 words, e.g. J. A. Harvey. String Duality and Non-supersymmetric
477             # Strings.
478             # if ($Text =~ /\b([\w\-'`"]+\s+){3,}[\w\-'"]+\b/){
479 1 50       10 if ($Text =~ /\.\s+([\w\-'`"]+\s+){3,}[\w\-'"]{2,}\b/){
480 1         3 $aText = $`;
481             };
482              
483 1 50       7 if ($Text =~ /[,;]\s*([\w\-'`"]{2,}\s+){3,}[\w\-'"]{2,}\b/) {
484 0         0 $aText = $`;
485             };
486             # the above has truncated too much.
487             # "S. Popescu and Sudbery G. A. Multi-particle entanglement ..."
488 1 50       4 if (only_initials($aText)) {
489 0         0 $aText = $Text
490             };
491              
492 1 50       9 if ($aText =~ /[,:; ]\s*[a-z][\w\-'"]*\s+([a-z0-9\-'"]+\s+)*?[a-z0-9\-'"]{4,}(\b|$)/) { # "[6] M.Gotay, Constraints, reduction and quantization,
493             # J. Math. Phys. (1986) 2051.
494 0         0 $aText = $`;
495             };
496            
497             # Or before the following sybmols.
498             # if ($aText =~ /["\[\(]/) {
499 1 50       5 if ($aText =~ /[:"\[\(]/) {
500 1         3 $aText = $`
501             };
502              
503              
504             # before '/', e.g. "Halzen F. astro-ph/0001001"
505 1 50       6 if ($aText =~ /\S+\//) {
506 0         0 $aText = $`
507             };
508              
509             # before any number
510 1 50       4 if ($aText =~ /\d+/i) {
511 0         0 $aText = $`
512             };
513              
514             # "14. A. J. Leggett, in Percolation, Localization and ..."
515 1 50       5 if ($aText =~ /[,;: ]\s*in /i) {
516 0         0 $aText = $`
517             };
518              
519             # last author name after 'and'.
520 1 50       5 if ($aText =~ /[,; ]\s*and ([^,;:]+)[,:;]([^,;:]+)/i) {
521 0         0 my $Aft1 = $1;
522 0         0 my $Aft2 = $2;
523 0 0       0 if (full_name($Aft1)) {
524 0         0 $aText = $` .", $Aft1";
525             } else {
526 0         0 $aText = $` .", $Aft1, $Aft2"
527             }
528             };
529              
530             #
531             # tidy up
532             #
533             # remove non-alphabets
534 1         3 $aText =~ s/^[^a-z]+//i;
535 1         3 $aText =~ s/^by //i;
536 1         2 $aText =~ s/[,; ]+and /,/i;
537 1         3 $aText =~ s/[,; ]+et\.?\s+al\.?([,; ]+|$)/,et al,/i;
538             #$aText =~ s/[,;:.]+\s*$//;
539 1         4 $aText =~ s/[,;:]+\s*$//;
540              
541 1         2 return $aText
542             };
543              
544             # This subroutine needs re-written; not in use now.
545             sub locate_book {
546 0     0 0 0 my $cite = shift;
547 0         0 my $Text = $cite->{'rest_text'};
548            
549 0 0       0 if ($Text =~ /\W+in\s+(.+?)\W+(ed|eds|edited)\.?(\W|$)/) {
550 0         0 $$cite{book} = $1;
551 0         0 return 1
552             };
553 0         0 return 0
554            
555             }
556              
557             sub find_vol_no {
558 0     0 0 0 my $cite = shift;
559 0         0 my $Text = $cite->{'rest_text'};
560            
561 0 0       0 if ($Text =~ s/[,;. ]\s*(?:volume|vol|v)?\.?\s*(\d+)\s*[ ,;]\s*(?:n|no|issue|\#)\.?\s*(\d+)\b/$1/is) {
562            
563 0         0 $cite->{'volume'} = $2;
564 0         0 $cite->{'issue'} = $3;
565 0         0 $cite->{'jnl_epos'} = length($`);
566 0         0 $cite->{'rest_text'} = $Text;
567 0         0 return 1
568             }
569 0         0 else { return 0}
570             }
571              
572             sub find_vol_supl {
573 0     0 0 0 my $cite = shift;
574 0         0 my $Text = $cite->{'rest_text'};
575            
576 0 0       0 if ($Text =~ s/(\s|,|;|\.)\s*(?:volume|vol|v)?\.?\s*(\d+)\s*[\s,;]\s*(?:supl|supplement)\.?\s*(\d+)\b/$1/is) {
577            
578 0         0 $cite->{'volume'} = $2;
579 0         0 $cite->{'supl'} = $3;
580 0         0 $cite->{'jnl_epos'} = length($`);
581 0         0 $cite->{'rest_text'} = $Text;
582             }
583             }
584              
585              
586             sub find_vol {
587 0     0 0 0 my $cite = shift;
588 0         0 my $Text = $cite->{'rest_text'};
589              
590 0 0       0 if ($Text =~ s/[,;:. ]\s*(?:volume|vol)[. ]\s*([a-z]*\d+[a-z]*)\b//i) {
591 0         0 $cite->{'volume'} = $1;
592 0         0 $cite->{'rest_text'} = $Text;
593             return
594 0         0 };
595              
596             # "..., Vol9 ..."
597 0 0       0 if ($Text =~ s/[,;:. ]\s*(?:volume|vol)(\d+[a-z]*)\b//i) {
598 0         0 $cite->{'volume'} = $1;
599 0         0 $cite->{'rest_text'} = $Text;
600             return
601 0         0 };
602              
603 0 0       0 if ($Text =~ s/[,;:. ]\s*(?:volume|vol)(\d+[a-z]*)\b//i) {
604 0         0 $cite->{'volume'} = $1;
605 0         0 $cite->{'rest_text'} = $Text;
606             return
607 0         0 };
608              
609             # beware: "Smith, V. 1990, Phys. Rev. A. v. 10 ..."
610 0         0 while ($Text =~ /[,;. ]\s*V\s*[. ]\s*([a-z]*\d+[a-z]*)\b/ig){
611 0         0 my $Guess_vol = $1;
612 0 0       0 next if ($Guess_vol =~ /(19|20)\d\d/);
613              
614 0         0 $cite->{'volume'} = $Guess_vol;
615 0         0 $Text =~ s/[,;. ]\s*V\s*[. ]\s*[a-z]*\d+[a-z]\b//i;
616 0         0 $cite->{'rest_text'} = $Text;
617             return
618 0         0 };
619              
620             # "... v10, ..."
621 0 0       0 if ($Text =~ s/[,;:. ]\s*V(\d+[a-z]*)\b//i) {
622 0         0 $cite->{'volume'} = $1;
623 0         0 $cite->{'rest_text'} = $Text;
624             return
625 0         0 };
626             }
627              
628             sub find_issue {
629 0     0 0 0 my $cite = shift;
630 0         0 my $Text = $cite->{'rest_text'};
631              
632 0 0       0 if ($Text =~ s/[,;:. ]\s*(?:number|issue|num|no|Nr|\#)[. ]\s*([a-z]*\d+[a-z]*)\b//i) {
633 0         0 $cite->{'issue'} = $1;
634 0         0 $cite->{'rest_text'} = $Text;
635             return
636 0         0 };
637              
638             # e.g. " ...No10, ..."
639 0 0       0 if ($Text =~ s/[,;:. ]\s*(?:number|issue|num|no|Nr)(\d+[a-z]*)\b//i) {
640 0         0 $cite->{'issue'} = $1;
641 0         0 $cite->{'rest_text'} = $Text;
642             return
643 0         0 };
644              
645 0         0 while ($Text =~ /[,;:. ]\s*N\s*[. ]\s*([a-z]*\d+[a-z]*)\b/ig){
646 0         0 my $Guess_issue = $1;
647 0 0       0 next if ($Guess_issue =~ /(19|20)\d\d/);
648              
649 0         0 $cite->{'issue'} = $Guess_issue;
650 0         0 $Text =~ s/[,;. ]\s*N\s*[. ]\s*[a-z]*\d+[a-z]*\b//i;
651             return
652 0         0 };
653              
654 0 0       0 if ($Text =~ s/[,;:. ]\s*(?:n|\#|\#\s+)(\d+[a-z]*)\b//i) {
655 0         0 $cite->{'issue'} = $1;
656 0         0 $cite->{'rest_text'} = $Text;
657             return
658 0         0 };
659            
660              
661             }
662              
663             sub find_supplement {
664 1     1 0 3 my $cite = shift;
665 1         3 my $Text = $cite->{'rest_text'};
666              
667 1 50       12 if ($Text =~ s/[,;:. ]\s*(?:suppl|supplement)\.?\s*(\d+)\b//i) {
668 0         0 $cite->{'supl'} = $1;
669 0         0 $cite->{'num_of_fig'} = $cite->{'num_of_fig'} - 1;
670 0         0 $cite->{'rest_text'} = $Text
671             }
672             }
673              
674              
675             sub find_url {
676 1     1 0 2 my $cite = shift;
677 1         3 my $Text = $cite->{'rest_text'};
678              
679 1 50       12 if ($Text =~ s/\b(http:\/\/[^\s]+)/ /i){
680 0         0 my $url = $1;
681 0         0 $url =~ s/\W*$//;
682 0         0 $cite->{'targetURL'} = $url;
683 0         0 $cite->{'rest_text'} = $Text;
684 0         0 return 1
685             };
686              
687 1 50       9 if ($Text =~ s/\b(http:\/\/[^\s>]+)(?:\s|$)/ /i){
688 0         0 $cite->{'targetURL'} = $1;
689 0         0 $cite->{'targetURL'} =~ s/[.,;]$//;
690 0         0 $cite->{'rest_text'} = $Text;
691 0         0 return 1
692             };
693              
694 1         2 return 0
695             }
696              
697              
698             sub find_page {
699 0     0 0 0 my $cite = shift;
700 0         0 my $Text = $cite->{'rest_text'};
701              
702             # keep the order of the pattern matching.
703              
704             # '... p.20, p 20, ...'
705 0 0       0 if ($Text =~ s/[,;:. ]\s*(?:pages|page|pp)\s*[.# ]\s*([a-z]*\d+[a-z]*)\b//i) {
706 0         0 $cite->{'spage'} = $1;
707 0         0 $cite->{'rest_text'} = $Text;
708             return
709 0         0 };
710              
711             # " ... pp20, ..."
712 0 0       0 if ($Text =~ s/[,;:. ]\s*(?:pages|page|pp)(\d+[a-z]*)\b//i) {
713 0         0 $cite->{'spage'} = $1;
714 0         0 $cite->{'rest_text'} = $Text;
715             return
716 0         0 };
717              
718             # ... p. 1990-1993
719 0 0       0 if ($Text =~ s/[,;. ]\s*(?:p)\s*[. ]\s*
720             ([a-z]*\d+[a-z]*)\s*\-\s*[a-z]*d+[a-z]*\b//xi) {
721            
722 0         0 $cite->{'spage'} = $1;
723 0         0 $cite->{'rest_text'} = $Text;
724             return
725 0         0 };
726              
727             # Beaware "Smith P. 1990, ..., p. 100"
728 0         0 while ($Text =~ /[,;. ]\s*p\s*[. ]\s*([a-z]*\d+[a-z]*)\s*(?!\-)/ig){
729 0         0 my $Guess_page = $1;
730 0 0       0 next if ($Guess_page =~ /(19|20)\d\d/);
731              
732 0         0 $cite->{'spage'} = $Guess_page;
733 0         0 $Text =~ s/[,;. ]\s*p\s*[. ]\s*[a-z]*\d+[a-z]*\s*(?!\-)//i;
734 0         0 $cite->{'rest_text'} = $Text;
735             return
736 0         0 };
737              
738             # " ... p20, ..."
739 0 0       0 if ($Text =~ s/[,;:. ]\s*p(\d+[a-z]*)\b//i) {
740 0         0 $cite->{'spage'} = $1;
741 0         0 $cite->{'rest_text'} = $Text;
742             return
743 0         0 };
744             }
745              
746              
747             sub find_year {
748 0     0 0 0 my $cite = shift;
749            
750 0 0       0 return 1 if ($cite->{'year'});
751            
752 0         0 my $Text = $cite->{'rest_text'};
753            
754             # priority is given to (1989) type.
755 0 0       0 if ($Text =~ s/\(((19|20)\d\d)\w?\)//) {
756 0         0 $cite->{'year'} = $1;
757 0         0 $cite->{'rest_text'} = $Text;
758 0         0 return 1
759             };
760            
761             # year like numbers not before/after a '-'
762             # e.g. 1966-1988 may indicate a page range.
763 0 0       0 if ($Text =~ /[^\w\-"]((19|20)\d\d)\w?([^\w\-"]|$)/i) {
764            
765 0         0 $cite->{'year'} = $1;
766 0         0 $Text =~ "\Q$` $'\E";
767 0         0 $cite->{'rest_text'} = $Text;
768 0         0 return 1
769             };
770            
771 0         0 return 0;
772             }
773              
774             # Apt'e, C., et al. ACM Transactions on Information Systems 12, 3, 233-251
775             sub guess_vol_no_pg {
776 0     0 0 0 my $cite = shift;
777 0 0 0     0 return 1 if ($cite->{'volume'} and $cite->{'issue'} and
      0        
778             $cite->{'spage'});
779 0 0       0 return 0 if ($cite->{'num_of_fig'} < 3);
780              
781 0         0 my $Text = $cite->{'rest_text'};
782              
783             # change (1,1) alike to ().
784 0         0 $Text =~ s/\(\d+\s*,\s*\d+\s*\)/\(\)/g;
785 0         0 $Text =~ s/\(\d+\s*;\s*\d+\s*\)/\(\)/g;
786              
787 0 0       0 if ($Text =~
788             /[^\w\/.-](?:volume|vol\.?|v\.?)?\s*([a-z]*?\d+[a-z]*?) # volume
789             [^\w\/.-]+(?:n|no|number|issue|\#)?\.?\s*([a-z]*?\d+[a-z]*?) # issue
790             [^\w\/.-]+(?:pages|page|pp|p)?\.?
791             \s*([a-z]*?\d+[a-z]*?)(?:\s*-\s*[a-z]*?\d+[a-z]*?)?
792             (\W*|$)/xi) {
793            
794 0         0 $cite->{'volume'} = $1;
795 0         0 $cite->{'issue'} = $2;
796 0         0 $cite->{'spage'} = $3;
797 0         0 $cite->{'jnl_epos'} = length($`) + 1;
798            
799 0         0 return 1
800             };
801              
802 0         0 return 0
803              
804             }
805              
806              
807             # '15:190' (15A:190-195, 14-15:190-180, or "Astrophys. J. 8, 103");
808             # Called this after '{find_vol_{no}_pg_year}' failed.
809             sub guess_vol_pg {
810 0     0 0 0 my $cite = shift;
811 0 0 0     0 return 1 if ($cite->{'volume'} and $cite->{'spage'});
812 0 0       0 return 0 if ($cite->{'num_of_fig'} < 2);
813            
814 0         0 my $Text = $cite->{'rest_text'};
815              
816             # change (1,1) alike to ().
817 0         0 $Text =~ s/\(\d+\s*,\s*\d+\s*\)/\(\)/g;
818 0         0 $Text =~ s/\(\d+\s*;\s*\d+\s*\)/\(\)/g;
819              
820             # 15A:190-195 type
821 0 0       0 if ($Text =~ s/[^\w\/.-]([a-z]*?\d+[a-z]*?)\s*:\s*([a-z]*?\d+[a-z]*?)\s*
822             (-\s*[a-z]*?\d+[a-z]*?)?(\W|$)/$4/xi) {
823 0         0 $cite->{'volume'} = $1;
824 0         0 $cite->{'spage'} = $2;
825 0         0 $cite->{'jnl_epos'} = length($`) + 1;
826              
827 0         0 $cite->{'rest_text'} = $Text;
828 0         0 return 1
829             };
830              
831             # Astrophys. J. Lett., 452, p.L91-L93
832             # AIP, vol 307, p.117, New York (1994).
833             # Pub. Astron. Soc. Japan, 2000, p.52
834 0 0       0 if ($Text =~
835             /[^\w\/.-](?:volume|vol\.?|v\.?)?\s*([a-z]*?\d+[a-z]*?) # volume
836             [^\w\/.-]*,\s*(?:p|pp|page|pages)[. ]\s*([a-z]*?\d+[a-z]*?)\s*
837             (-\s*[a-z]*?\d+[a-z]*?)?(?:\W|$)/xi) {
838              
839 0         0 my $Guess_vol = $1;
840 0         0 $cite->{'spage'} = $2;
841 0         0 my $Guess_jnl_epos = length($`) + 1; # prematch
842            
843 0 0       0 if ($Guess_vol =~ /^(19|20)\d\d[a-z]?$/i) {
844 0         0 $cite->{'year'} = $Guess_vol;
845 0         0 $cite->{'rest_text'} =~
846             s/([^\w\/.-])(?:volume|vol\.?|v\.?)?\s*[a-z]*?\d+[a-z]*?\s*,\s*(?:p|pp|page|pages)\s*\.?[a-z]*?\d+[a-z]*?\s*(-\s*[a-z]*?\d+[a-z]*?)?(\W|$)/$1/i;
847 0         0 return 0
848             };
849 0         0 $cite->{'volume'} = $Guess_vol;
850 0         0 $cite->{'jnl_epos'} = $Guess_jnl_epos;
851 0         0 $cite->{'rest_text'} =~
852             s/([^\w\/.-])[a-z]*?\d+[a-z]*?\s*,\s*(?:p|pp|page|pages)\s*\.?[a-z]*?\d+[a-z]*?\s*(-\s*[a-z]*?\d+[a-z]*?)?(\W|$)/$1/i;
853 0         0 return 1
854             };
855              
856             # Elias, J. 1994, NOAO Newsletter, No. 37, 1
857 0 0       0 if ($Text =~
858             /[^\w\/.-](?:n|no|num|issue)[. ]\s*([a-z]*?\d+[a-z]*?) # volume
859             [^\w\/.-]*,\s*(?:p|pp|page|pages)?\.?\s*([a-z]*?\d+[a-z]*?)\s*
860             (-\s*[a-z]*?\d+[a-z]*?)?(?:\W|$)/xi) {
861            
862 0         0 $cite->{'issue'} = $1;
863 0         0 $cite->{'spage'} = $2;
864 0         0 $cite->{'jnl_epos'} = length($`) + 1; # prematch
865 0         0 $cite->{'rest_text'} =~
866             s/([^\w\/.-])(?:n|no|num|issue)[. ]\s*[a-z]*?\d+[a-z]*?[^\w\/.-]*,\s*(?:p|pp|page|pages)?\.?\s*([a-z]*?\d+[a-z]*?)\s*(-\s*[a-z]*?\d+[a-z]*?)?(?:\W|$)/$1/i;
867 0         0 return 1
868             };
869              
870             # match page range.
871             # Phys. Rev. A 4, 52-60
872             # Pub. Astron. Soc. Japan, 1998, 52-60
873 0 0       0 if ($Text =~ /[^\w\/.-]([a-z]*?\d+[a-z]*?) # volume or year
874             [^\w\/.-]*[, ]\s*([a-z]*?\d+[a-z]*?)\s* # pages
875             -\s*[a-z]*?\d+[a-z]*?(?:[^\w-]|$)/xi) {
876              
877 0         0 my $Guess_vol = $1;
878 0         0 $cite->{'spage'} = $2;
879 0         0 my $Guess_jnl_epos = length($`) + 1; # prematch
880            
881 0 0       0 if ($Guess_vol =~ /^(19|20)\d\d[a-z]?$/i) {
882 0         0 $cite->{'year'} = $Guess_vol;
883 0         0 $cite->{'rest_text'} =~
884             s/([^\w\/.-])[a-z]*?\d+[a-z]*?\s*[, ]\s*([a-z]*?\d+[a-z]*?)\s*-\s*[a-z]*?\d+[a-z]*?(?:[^\w\/.-]|$)/$1/i;
885 0         0 return 0
886             };
887 0         0 $cite->{'volume'} = $Guess_vol;
888 0         0 $cite->{'jnl_epos'} = $Guess_jnl_epos;
889 0         0 $cite->{'rest_text'} =~ s/([^\w\/.-])[a-z]*?\d+[a-z]*?\s*,\s*([a-z]*?\d+[a-z]*?)\s*-\s*[a-z]*?\d+[a-z]*?(?:[^\w\/.-]|$)/$1/i;
890              
891 0         0 return 1
892             };
893              
894             # Phys. Rev. B 38, 2297. (Phys. Rev. B 38 2297)
895             # Pub. Astron. Soc. Japan, 2000, 52.
896 0 0       0 if ($Text =~ /[^\w\/.-]([a-uw-z]*?\d+[a-z]*?)
897             [^\w\/.-]*[, ]\s*([a-z]?\d+[a-z]?)(?:[^\w\/.-]|$)/xi) {
898              
899 0         0 my $Guess_vol = $1;
900 0         0 my $Guess_page = $2;
901 0         0 $cite->{'jnl_epos'} = length($`) + 1;
902              
903 0 0       0 if ($Guess_vol =~ /^(19|20)\d\d[a-z]?$/i) {
904 0         0 $cite->{'year'} = $Guess_vol;
905             } else {
906 0         0 $cite->{'volume'} = $Guess_vol;
907             };
908              
909 0 0       0 if ($Guess_page =~ /^(19|20)\d\d[a-z]?$/i) {
910 0         0 $cite->{'year'} = $Guess_page;
911             } else {
912 0         0 $cite->{'spage'} = $Guess_page;
913             };
914            
915 0         0 $cite->{'rest_text'} =~
916             s/([^\w\/.-])[a-z]*?\d+[a-z]*?[^\w\/.-]*[, ]\s*[a-z]*?\d+[a-z]*?(?:[^\w\/.-]|$)/$1/i;
917 0 0 0     0 return 1 if ($cite->{'volume'} and $cite->{'spage'});
918 0         0 return 0
919             };
920            
921 0         0 return 0
922             };
923              
924             #
925             # G. Smith and H. Gray; Pub. Astron. Soc. Japan, 2000, vol. 52
926             # To find $cite->{'jnl_epos'} currectly. Note that '2000' may be
927             # regarded as the journal name (by subroutine find_vol).
928             sub guess_vol_year {
929 0     0 0 0 my $cite = shift;
930 0 0       0 return 0 if ($cite->{'num_of_fig'} < 2);
931            
932 0         0 my $Text = $cite->{'rest_text'};
933              
934             # change (1,1) alike to ().
935 0         0 $Text =~ s/\(\d+\s*,\s*\d+\s*\)/\(\)/g;
936 0         0 $Text =~ s/\(\d+\s*;\s*\d+\s*\)/\(\)/g;
937            
938 0 0       0 if ($Text =~
939             /[^\w\/.-]\(?((19|20)\d\d)\w?\)?[^\w\/.-]*
940             (?:volume|vol|v)\W*([a-oq-z]*?\d+[a-z]*?)(\W|$)/xis) {
941            
942 0         0 $cite->{'year'} = $1;
943 0         0 $cite->{'volume'} = $3;
944 0         0 $cite->{'jnl_epos'} = length($`);
945            
946 0         0 return 1
947             };
948              
949             # be aware: "Workshop on ..., p30 (1999)."
950 0 0       0 if ($Text =~
951             /[^\w\/.-](?:volume|vol|v)?\W*([a-oq-z]?\d+[a-z]?)
952             [^\w\/.-]+\(?((19|20)\d\d)\w?\)?(\W|$)/xis) {
953 0         0 $cite->{'volume'} = $1;
954 0         0 $cite->{'year'} = $2;
955 0         0 $cite->{'jnl_epos'} = length($`);
956              
957 0         0 return 1
958             };
959            
960 0         0 return 0
961             };
962            
963             sub find_vol_no_pg_year {
964 1     1 0 2 my $cite = shift;
965 1 0 33     6 return 1 if ($cite->{'volume'} and $cite->{'issue'} and
      33        
      0        
966             $cite->{'spage'} and $cite->{'year'});
967 1 50       13 return 0 if ($cite->{'num_of_fig'} < 4);
968            
969 0         0 my $Text = $cite->{'rest_text'};
970              
971             # change (1,1) alike to ().
972 0         0 $Text =~ s/\(\d+\s*,\s*\d+\s*\)/\(\)/g;
973 0         0 $Text =~ s/\(\d+\s*;\s*\d+\s*\)/\(\)/g;
974              
975             # Keep the following order of texting $Text;
976             # Important: check 'year' at the end first.
977            
978             # (A.1):
979             # 'year' is at the end, within bracket.
980             # ..., v.517, no. 1, p.190-200, (1999)
981             # ..., 11(2), 100-105, (1999)
982 0 0       0 if ($Text =~
983             /[^\w\/.-](?:volume|vol\.?|v\.?)?\s*([a-z]*?\d+[a-z]*?) # volume
984             [^\w\/.-]+(?:n|no|number|issue|\#)?\.?\s*([a-z]*?\d+[a-z]*?) # issue
985             [^\w\/.-]+(?:pages|page|pp|p)?\.?
986             \s*([a-z]*?\d+[a-z]*?)(?:\s*-\s*[a-z]*?\d+[a-z]*?)?
987             \W*\(((19|20)\d\d)[a-z]*?\)(\W|$)/xi) {
988            
989 0         0 $cite->{'volume'} = $1;
990 0         0 $cite->{'issue'} = $2;
991 0         0 $cite->{'spage'} = $3;
992 0         0 $cite->{'year'} = $4;
993 0         0 $cite->{'jnl_epos'} = length($`) + 1;
994            
995 0         0 return 1
996             };
997            
998             # (A.2) 'year' is in the middle, within bracket.
999             # ..., 4(2), (1999), 100-105
1000 0 0       0 if ($Text =~
1001             /[^\w\/.-](?:volume|vol\.?|v\.?)?\s*([a-z]*?\d+[a-z]*?) # volume
1002             [^\w\/.-]+(?:n|no|number|issue|\#)?\.?\s*([a-z]*?\d+[a-z]*?) # issue
1003             \W*\(((19|20)\d\d)[a-z]*?\) # year
1004             \W*(?:pages|page|pp|p)?\.?\s*([a-z]*?\d+[a-z]*?)(\W|$)/xi) {
1005            
1006 0         0 $cite->{'volume'} = $1;
1007 0         0 $cite->{'issue'} = $2;
1008 0         0 $cite->{'year'} = $3;
1009 0         0 $cite->{'spage'} = $5;
1010 0         0 $cite->{'jnl_epos'} = length($`) + 1;
1011              
1012 0         0 return 1
1013             };
1014            
1015             # (A.3.1) 'year' is at the beginning, within bracket, after
1016             # journal title;
1017             # ...., (1999), 517, no. 1, p.190-200
1018 0 0       0 if ($Text =~
1019             /\(((19|20)\d\d)[a-z]*?\)[,.;\s:]* # year
1020             (?:volume|vol|v)?\.?\s*([a-z]*?\d+[a-z]*?) # volume
1021             [^\w\/.-]+(?:n|no|number|issue|\#)?\.?\s*([a-z]*?\d+[a-z]*?) # issue
1022             [^\w\/.-]+(?:pages|page|pp|p)?\.?\s*([a-z]*?\d+[a-z]*?)(\W|$)/ix)
1023             {
1024 0         0 $cite->{'year'} = $1;
1025 0         0 $cite->{'volume'} = $3;
1026 0         0 $cite->{'issue'} = $4;
1027 0         0 $cite->{'spage'} = $5;
1028 0         0 $cite->{'jnl_epos'} = length($`);
1029              
1030 0         0 return 1;
1031             };
1032              
1033             # (A.3.2) 'year' is at the beginning, within bracket, before
1034             # journal title;
1035             # ..., (1999),..., 517, no. 1, p.190-200
1036 0 0       0 if ($Text =~
1037             /\(((19|20)\d\d)[a-z]*?\) # year
1038             ([^(]+?)
1039             [^\w\/.-](?:volume|vol|v)?\.?\s*([a-z]*?\d+[a-z]*?) # volume
1040             [^\w\/.-]+(?:n|no|number|issue|\#)?\.?\s*([a-z]*?\d+[a-z]*?) # issue
1041             [^\w\/.-]+(?:pages|page|pp|p)?\.?\s*([a-z]*?\d+[a-z]*?)(\W|$)/ix){
1042 0         0 $cite->{'year'} = $1;
1043 0         0 $cite->{'volume'} = $4;
1044 0         0 $cite->{'issue'} = $5;
1045 0         0 $cite->{'spage'} = $6;
1046              
1047             # $cite->{'jnl_spos'} = length($`);
1048             # $cite->locate_jnl_epos();
1049 0         0 $cite->{'jnl_epos'} = length($`) + length($1) +
1050             length($3);
1051 0         0 return 1;
1052             };
1053            
1054            
1055             # (B.1):
1056             # 'year' is at the end, but not in bracket;
1057             # ..., v.517, no. 1, p.190-200, 1999
1058             # ..., 517, no. 1, p.190-200, 1999
1059 0 0       0 if ($Text =~
1060             /[^\w\/.-](?:volume|vol\.?|v\.?)?\s*([a-z]*?\d+[a-z]*?) # volume
1061             [^\w\/.-]+(?:n|no|number|issue|\#)?\.?\s*([a-z]*?\d+[a-z]*?) # issue
1062             [^\w\/.-]+(?:pages|page|pp|p)?\.?
1063             \s*([a-z]*?\d+[a-z]*?)(?:\s*-\s*[a-z]*?\d+[a-z]*?)?
1064             [^\w(:\/.-]+?((19|20)\d\d)[a-z]?\s*(?![)-])/xi) {
1065            
1066 0         0 $cite->{'volume'} = $1;
1067 0         0 $cite->{'issue'} = $2;
1068 0         0 $cite->{'spage'} = $3;
1069 0         0 $cite->{'year'} = $4;
1070 0         0 $cite->{'jnl_epos'} = length($`) + 1;
1071            
1072 0         0 return 1
1073             };
1074            
1075            
1076             # (B.2): 'year' is in the middle, but not in bracket.
1077             # 4(2), 1999, 100-105
1078 0 0       0 if ($Text =~
1079             /[^\w\/.-](?:volume|vol\.?|v\.?)?\s*([a-z]*?\d+[a-z]*?) # volume
1080             [^\w\/.-]+(?:n|no|number|issue|\#)?\.?\s*([a-z]*?\d+[a-z]*?) # issue
1081             [^\w(:\/.-]+?\s*((19|20)\d\d)[a-z]? # year
1082             \s*[^\w\/.)-]+?\s*(?:pages|page|pp|p)?\.?\s*([a-z]*?\d+[a-z]*?)(\W|$)/xi) {
1083            
1084 0         0 $cite->{'volume'} = $1;
1085 0         0 $cite->{'issue'} = $2;
1086 0         0 $cite->{'year'} = $3;
1087 0         0 $cite->{'spage'} = $5;
1088 0         0 $cite->{'jnl_epos'} = length($`) + 1;
1089            
1090 0         0 return 1
1091             };
1092            
1093             # (B.3.1): 'year' is at beginning, not in bracket, after title;
1094             # ..., 1999, v.517, no. 1, p.190-200
1095             # " ... 1890-1999", MNRAS, 2000, 4:1, p 1990
1096 0 0       0 if ($Text =~
1097             /[^"(\/.-]\s*((19|20)\d\d)[a-z]?[,;\.\s]+ # year
1098             (?:volume|vol|v)?\.?\s*([a-z]*?\d+[a-z]*?) # volume
1099             [^\w\/.-]+?(?:n|no|number|issue|\#)?\.?\s*([a-z]*?\d+[a-z]*?)
1100             [^\w\/.-]+(?:pages|page|pp|p)?\.?\s*([a-z]*?\d+[a-z]*?)(\W|$)/ix)
1101             {
1102 0         0 $cite->{'year'} = $1;
1103 0         0 $cite->{'volume'} = $3;
1104 0         0 $cite->{'issue'} = $4;
1105 0         0 $cite->{'spage'} = $5;
1106 0         0 $cite->{'jnl_epos'} = length($`) + 1;
1107 0         0 return 1
1108             };
1109            
1110             # (B.3.2): 'year' is at beginning, not in bracket, before title;
1111             # 1999, ..., v.517, no. 1, p.190-200
1112             # 1999, ..., 517, no. 1, p.190-200
1113             # 1999, ..., 517(1), 190-200
1114             # NB: 1999, "... 1.5 factor ....", 517(1), 190-200
1115             # NB: B. Greene, editors, "Fields, Strings and Duality, TASI 1996",
1116             # pages 421-540, World Scientific, 1997.
1117             # " ... 1890-1999", MNRAS, 2000, 4:1, p 1990
1118 0 0       0 if ($Text =~
1119             /(?:^|[^"(\/.-])\s*((19|20)\d\d)[a-z]? # year
1120             [^\w:")(\/-][^(]*?
1121             [^\w\/.-](?:volume|vol|v)?\.?\s*([a-z]*?\d+[a-z]*?) # volume
1122             [^\w\/.-]+?(?:n|no|number|issue|\#)?\.?\s*([a-z]?\d+[a-z]?)
1123             [^\w\/.-]+(?:pages|page|pp|p)?\.?\s*([a-z]*?\d+[a-z]*?)(\W|$)/ix)
1124             {
1125 0         0 $cite->{'year'} = $1;
1126 0         0 $cite->{'volume'} = $3;
1127 0         0 $cite->{'issue'} = $4;
1128 0         0 $cite->{'spage'} = $5;
1129              
1130 0         0 $cite->{'jnl_spos'} = length($`);
1131 0         0 $cite->locate_jnl_epos();
1132 0         0 return 1
1133             };
1134 0         0 return 0
1135             };
1136            
1137              
1138             # For cases where 'vol, page, year' can be identified correctly.
1139             sub find_vol_pg_year {
1140 1     1 0 2 my $cite = shift;
1141 1 0 33     6 return 1 if ($cite->{'volume'} and $cite->{'spage'} and
      33        
1142             $cite->{'year'});
1143 1 50       4 return 0 if ($cite->{'num_of_fig'} < 3);
1144            
1145 1         2 my $Text = $cite->{'rest_text'};
1146              
1147             # change (1,1) alike to ().
1148 1         4 $Text =~ s/\(\d+\s*,\s*\d+\s*\)/\(\)/g;
1149 1         5 $Text =~ s/\(\d+\s*;\s*\d+\s*\)/\(\)/g;
1150            
1151             # (A.1) 'year' is at the end, within bracket.
1152             # ......, vol.8:100, (1999)
1153             # ......, 8:100, (1999)
1154             # ~~~~
1155 1 50       15 if ($Text =~
1156             /(?:^|[^\w\/.-])(?:volume|vol\.?|v\.?)?\s*([a-z]*?\d+[a-z]*?) # volume
1157             [^\w\/.-]+(?:pages|page|pp|p)?\.?
1158             \s*([a-z]?\d+[a-z]?)(?:\s*-\s*[a-z]?\d+[a-z]?)?
1159             \W*\(((19|20)\d\d)[a-z]?\)(\W|$)/xi) {
1160            
1161 0         0 $cite->{'volume'} = $1;
1162 0         0 $cite->{'spage'} = $2;
1163 0         0 $cite->{'year'} = $3;
1164 0         0 $cite->{'jnl_epos'} = length($`) + 1;
1165            
1166 0         0 return 1
1167             };
1168            
1169             # (A.2) 'year' is in the middle, within bracket.
1170             # ......, 8, (1999), 100-105
1171 1 50       13 if ($Text =~
1172             /(?:^|[^\w\/.-])(?:volume|vol\.?|v\.?)?\s*([a-z]*?\d+[a-z]*?) # volume
1173             \W*\(((19|20)\d\d)[a-z]?\) # year
1174             \W*(?:pages|page|pp|p)?\.?
1175             \s*([a-z]?\d+[a-z]?)(?:\s*-\s*[a-z]?\d+[a-z]?)?(\W|$)/xi) {
1176            
1177 0         0 $cite->{'volume'} = $1;
1178 0         0 $cite->{'year'} = $2;
1179 0         0 $cite->{'spage'} = $4;
1180 0         0 $cite->{'jnl_epos'} = length($`) + 1;
1181            
1182 0         0 return 1
1183             };
1184            
1185             # (A.3.1.) 'year' is at beginning, within bracket, after title;
1186             # ......, (1999) 517, 190-200
1187 1 50       13 if ($Text =~
1188             /\(((19|20)\d\d)[a-z]?\)[,;\.\s]* # year
1189             (?:volume|vol|v)?\.?\s*([a-z]*?\d+[a-z]*?) # volume
1190             [^\w\/.-]+(?:pages|page|pp|p)?\.?\s*([a-z]?\d+[a-z]?)(\W|$)/ix){
1191 0         0 $cite->{'year'} = $1;
1192 0         0 $cite->{'volume'} = $3;
1193 0         0 $cite->{'spage'}= $4;
1194 0         0 $cite->{'jnl_epos'} = length($`);
1195            
1196 0         0 return 1;
1197             };
1198              
1199             # (A.3.1.1) 'year' is at beginning, within bracket, after title;
1200             # not 'vol', buy 'No.@, e.g."..., (1999) No. 517, 190-200
1201 1 50       16 if ($Text =~
1202             /\(((19|20)\d\d)[a-z]?\)[,;\.\s]* # year
1203             (?:number|no|n)\.?\s*([a-z]*?\d+[a-z]*?) # volume
1204             [^\w\/.-]+(?:pages|page|pp|p)?\.?\s*([a-z]?\d+[a-z]?)(\W|$)/ix){
1205 0         0 $cite->{'year'} = $1;
1206 0         0 $cite->{'volume'} = $3;
1207 0         0 $cite->{'spage'}= $4;
1208 0         0 $cite->{'jnl_epos'} = length($`);
1209            
1210 0         0 return 1;
1211             };
1212            
1213              
1214             # (A.3.2.) 'year' is at beginning, within bracket, before title;
1215             # ..., (1999),..., 517, p.190-200
1216 1 50       27 if ($Text =~
1217             /\(((19|20)\d\d)[a-z]?\) # year
1218             [^(]+?
1219             [^\w\/.-](?:volume|vol|v)?\.?\s*([a-z]*?\d+[a-z]*?) # volume
1220             [^\w\/.-]+(?:pages|page|pp|p)?\.?\s*([a-z]?\d+[a-z]?)(\W|$)/ix){
1221 1         4 $cite->{'year'} = $1;
1222 1         5 $cite->{'volume'} = $3;
1223 1         6 $cite->{'spage'} = $4;
1224              
1225 1         3 $cite->{'jnl_spos'} = length($`);
1226 1         6 $cite->locate_jnl_epos();
1227 1         7 return 1;
1228             };
1229              
1230             # (B.1) 'year' is at the end, but not in bracket.
1231             # ......, vol.8:100, 1999
1232             # ......, 8:100, 1999
1233             # NB: ..., 1999, 8(1900)
1234             # ~~~~
1235 0 0       0 if ($Text =~
1236             /[^\w\/.-](?:volume|vol\.?|v\.?)?\s*([a-z]*?\d+[a-z]*?) # volume
1237             [^\w\/.-]+(?:pages|page|pp|p)?\.?
1238             \s*([a-z]?\d+[a-z]?)(?:\s*-\s*[a-z]?\d+[a-z]?)? # page
1239             [^\w:(\/.-]+\s*((19|20)\d\d)[a-z]?\s*(?![)-])/xi) {
1240            
1241 0         0 $cite->{'volume'} = $1;
1242 0         0 $cite->{'spage'} = $2;
1243 0         0 $cite->{'year'} = $3;
1244 0         0 $cite->{'jnl_epos'} = length($`) + 1;
1245            
1246 0         0 return 1
1247             };
1248            
1249             # (B.2) 'year' is in the middle, but not in brackets;
1250             # ... 8, 1999, p.100
1251             # ... 8, 1999, 100-105
1252 0 0       0 if ($Text =~
1253             /[^\w\/.-](?:volume|vol\.?|v\.?)?\s*([a-z]*?\d+[a-z]*?) # volume
1254             [^\w:(\/.-]+?\s*((19|20)\d\d)[a-z]? # year
1255             [^\w\/.)-]+(?:pages|page|pp|p)?\.?\s*([a-z]?\d+[a-z]?)(\W|$)/xi)
1256             {
1257 0         0 $cite->{'volume'} = $1;
1258 0         0 $cite->{'year'} = $2;
1259 0         0 $cite->{'spage'} = $4;
1260 0         0 $cite->{'jnl_epos'} = length($`) + 1;
1261            
1262 0         0 return 1
1263             };
1264              
1265             # (B.3.1) 'year' is at the beginning,not in bracket, after title;
1266             # ..., 1999, 8, p1990
1267 0 0       0 if ($Text =~
1268             /[^\w\/.(-]\s*((19|20)\d\d)[a-z]?[,;\.\s]+
1269             (?:volume|vol|v)?\.?\s*([a-z]*?\d+[a-z]*?) # volume
1270             [^\w\/.-]+(?:pages|page|pp|p)?\.?\s*([a-z]?\d+[a-z]?)(\W|$)/ix){
1271 0         0 $cite->{'year'} = $1;
1272 0         0 $cite->{'volume'} = $3;
1273 0         0 $cite->{'spage'} = $4;
1274 0         0 $cite->{'jnl_epos'} = length($`)+1;
1275 0         0 return 1
1276             };
1277              
1278             # (B.3.1.1) 'year' is at the beginning,not in bracket, after title;
1279             # no 'vol', but 'no.' e.g. ..., 1999, No. 8, p1990
1280 0 0       0 if ($Text =~
1281             /[^\w\/.(-]\s*((19|20)\d\d)[a-z]?[,;\.\s]+
1282             (?:number|no|n)\.?\s*([a-z]*?\d+[a-z]*?) # no volume, but issues
1283             [^\w\/.-]+(?:pages|page|pp|p)?\.?\s*([a-z]?\d+[a-z]?)(\W|$)/ix){
1284 0         0 $cite->{'year'} = $1;
1285 0         0 $cite->{'issue'} = $3;
1286 0         0 $cite->{'spage'} = $4;
1287 0         0 $cite->{'jnl_epos'} = length($`)+1;
1288 0         0 return 1
1289             };
1290              
1291            
1292             # (B.3.2) 'year' is at beginning, not in bracket, before title;
1293             # 1999, ..., 8(100)
1294 0 0       0 if ($Text =~
1295             /((^|[^"\/.(-])\s*)(((19|20)\d\d)[a-z]?) # year
1296             ([^\w:")(\/][^(]*?)
1297             [^\w\/.-](?:volume|vol|v)?\.?\s*([a-z]*?\d+[a-z]*?) # volume
1298             [^\w\/.-]+(?:pages|page|pp|p)?\.?\s*([a-z]?\d+[a-z]?)(\W|$)/ix){
1299 0         0 $cite->{'year'} = $4;
1300 0         0 $cite->{'volume'} = $7;
1301 0         0 $cite->{'spage'} = $8;
1302            
1303             # $cite->{'jnl_spos'} = length($`);
1304             # $cite->locate_jnl_epos();
1305 0         0 $cite->{'jnl_epos'} = length($`) + length($1) +
1306             length($3) + length($6);
1307 0         0 return 1
1308             };
1309            
1310 0         0 return 0
1311             }
1312              
1313              
1314             # This subroutine is only called when the journal title is between
1315             # 'year' and 'vol/page', e.g. (a lot in astro-ph/)
1316             # Barnes, J., Efstathiou, G., 1987, ApJ, 319, 575
1317             # For other cases, the cite{'jnl_epos'} is determined while trying to
1318             # find out the vol, page, year, i.e. in 'find_vol_no_pg_year' kind
1319             # of subroutines.
1320             #
1321             sub locate_jnl_epos {
1322            
1323 1     1 0 3 my $cite = shift;
1324 1         3 my $sPos = $cite->{'jnl_spos'};
1325 1         3 my $Text = substr($cite->{'rest_text'}, $sPos);
1326            
1327             # $Text =~ s/(\W+)(?:pages|page|pp|p)\W*(\d+)/$1$2/;
1328             # $Text =~ s/-\d+[a-z]*?//; # pp100-105
1329            
1330             # Before 'volume'
1331 1 50       11 if ($Text =~ /\b(?:volume|vol\.?|v\.?)\s*[a-z]*?\d+[a-z]*?(?![.0-9])/i) {
1332 0         0 $cite->{'jnl_epos'} = length($`) + $sPos;
1333 0         0 return 1
1334             };
1335              
1336             # (1997) Phys. Rev. E56, No.3, 2875
1337             # (1997) Phys. Rev. A50, p.160
1338 1 50       28 if ($Text =~ /
1339             [^\w\/.-](?:volume|vol\.?|v\.?)?\s*[a-z]*?\d+[a-z]*? # volume
1340             [^\w\/.-]+(?:n |n.|no |no.|number |issue |\#|p |p.|pp.|page )\s*[a-z]*?\d+[a-z]*?
1341             (?:\W|$)/xi) {
1342 0         0 $cite->{'jnl_epos'} = length($`) + $sPos + 1 ;
1343 0         0 return 1
1344             };
1345              
1346             # Before any two consecutive numbers, but not '123-127' style page.
1347             # Bertelli, G., 1999, ApJ, 517(1), ....
1348             # ApJ, 517:1, ...
1349             # ApJ, 517:367-380.
1350             #Beaware: J.K. Lanyi. 1999. Structure of bacteriorhodopsin at 1.55
1351             # angstrom resolution J. Mol. Bio. 291:899-911 ~~~~!
1352 1 50       20 if ($Text =~ /[^\w\/.-][a-z]*?\d+[a-z]*?\s*[,:(\s]\s*
1353             [a-z]?\d+[a-z]?(\W|$)/xi) {
1354 1         4 $cite->{'jnl_epos'} = length($`) + $sPos + 1;
1355 1         3 return 1
1356             };
1357            
1358 0         0 return 0
1359             };
1360              
1361              
1362             sub find_jnl_name {
1363 1     1 0 2 my $cite = shift;
1364            
1365 1 50       5 return 1 if ($cite->{'title'});
1366 1 50       5 return 0 if (! $cite->{'jnl_epos'});
1367              
1368             # Assumption: journal name usually starts after a ',;'
1369             # or " which is used to enclose the article title,
1370             # and does not contain those symbols (i.e. ,;")
1371             #
1372 1         4 my $Text = substr($cite->{'rest_text'}, 0, $cite->{'jnl_epos'});
1373 1         2 my $Guess_jnl;
1374              
1375             # Linden, N., et al. quantph/9711016 and Fortsch. Phys. 46, 567 (1998)
1376             #if ($Text =~ m{[^/]+/\w+\s*(.+)$}) {
1377             # $Text = $1
1378             # };
1379              
1380 1         33 LOOP:
1381             # remove trailing symbols
1382             $Text =~ s/\s*[,;":\/\[\(]*\s*$//s;
1383              
1384             # ignore anything in brackets (head/tail position)
1385 1         12 $Text =~ s/\W*\([^\)]+\)?\W*$//;
1386 1         4 $Text =~ s/^\s*\([^\)]+\)\W+//;
1387              
1388 1 50       4 return 0 if ($Text eq '');
1389              
1390             # quite many citations are like this:
1391             # "P. Reiter, et al:Phys. Rev. Lett. 82 (1999) 509"
1392             # hard to separate name from journal title. Other cases
1393             # are: '..., J.PHY.G:NUCL.PART.PHY.'. Have to compramise.
1394 1 50       9 if ($Text =~ /([^,;":?\/\[]+)$/) {
1395 1         3 $Guess_jnl = $1;
1396 1         5 $Guess_jnl =~ s/^['`]?\s*//;
1397 1         6 $Guess_jnl =~ s/\s+$//;
1398              
1399             # ignore things in brackets
1400 1         10 $Guess_jnl =~ s/\W*\([^\)]+\)?\W*$//;
1401 1         4 $Guess_jnl =~ s/^\([^\)]+\)\W*//;
1402              
1403             # journal name should begin and contain alphabet,
1404             # not only numbers; and should be longer than one
1405             # character. First remove 'year'
1406 1         7 $Guess_jnl =~ s/^.*?\(?(19|20)\d\d\w*\)?\W*//;
1407 1 50       8 if ($Guess_jnl =~ /^[a-z]\W*$/i) {
1408 0         0 $Text =~ s/[^,;":?\/\[]+$//;
1409             goto LOOP
1410 0         0 };
1411              
1412             # No captital letters
1413 1 50       5 if ($Guess_jnl !~ /[A-Z]/) {
1414 0         0 $Text =~ s/[^,;":?\/\[]+$//;
1415             goto LOOP
1416 0         0 };
1417              
1418             # "Report of ... Conf.:1. Introduction. Canadian Medical Association Journal"
1419 1 50       9 if ($Guess_jnl !~ /^[a-z]+/i) {
1420 0         0 my @gWords = split(/\s+/, $Guess_jnl);
1421              
1422 0 0       0 if (scalar(@gWords) <= 3) {
1423 0         0 $Text =~ s/[^,;":?\/]+$//;
1424             goto LOOP
1425 0         0 }
1426             };
1427              
1428 1         4 $Text = $Guess_jnl;
1429             }
1430             else {
1431 0         0 $Text =~ s/^[`']?\s*//;
1432 0         0 $Text =~ s/\s*$//;
1433              
1434             # 'title' is after 'year' (other cases are dealt by
1435             # $cite->{'jnl_epos'} in 'find_vol_{no}_pg_year()'..
1436 0 0       0 if ($Text =~ /[,\s\(]+(19|20)\d\d[,\s\)]+\s*/) {
1437 0         0 $Text = $'
1438             };
1439             };
1440            
1441 1         2 my $end_dot = 0;
1442 1 50       5 $end_dot = 1 if ($Text =~ /\.$/);
1443 1         4 my @Title_words = ();
1444 1         2 my @Words = ();
1445 1         3 my $i = 0;
1446              
1447             # process from the end of the $Text to see if
1448             # a $Parts[$i] is (still) a part of a journal name.
1449 1         8 my @Parts = split(/\s*\.\s*/, $Text);
1450 1         6 for ($i = $#Parts; $i>=0; $i--) {
1451 1 50       6 next if ($Parts[$i] !~ /[a-z]/i);
1452              
1453             # author name may be mixed into the journal title
1454             # e.g. "Popescu S. and G. A. Sudbery. J. of Phy ..."
1455 1 50 33     11 if ($i > 0 and $Parts[$i-1] =~ /^([A-Z][a-z]* )*and\s+[A-Z]$/) {
1456             last
1457 0         0 };
1458 1 50 33     5 if ($i > 1 and $Parts[$i-2] =~ /^([A-Z][a-z]* )*and\s+[A-Z]$/) {
1459 0 0       0 last if ($Parts[$i-1] =~ /^[A-Z]$/);
1460             };
1461              
1462             # author name may be mixed into the journal title
1463             # e.g. "and Sudbery A. Multi-particle ..."
1464 1 50 33     9 if ($i > 0 and $Parts[$i] =~ /^[A-Z]$/) {
1465             # less than 4 words.
1466 0 0 0     0 if ($Parts[$i-1] =~ /^\S+\s+\S+(\s+\S+){0,2}$/ and
1467             $Parts[$i-1] =~ /^(and )?[A-Z].+?[A-Z]$/){
1468             last
1469 0         0 }
1470             };
1471              
1472 1         2 push(@Title_words, $Parts[$i]);
1473 1 50       4 last if $i == 0; # necessary test
1474              
1475 1 50       5 last if ($Parts[$i-1] =~ /et\s+al$/i);
1476 1 50       6 last if ($Parts[$i-1] =~ /^\s*\d+$/);
1477              
1478 1         6 @Words = split(/\s+/, $Parts[$i-1]);
1479             # stop if more than 4 words in $Parts[$i-1],
1480             # i.e. $Parts[$i-1] seems to contain article title,
1481             # not the journal name. However, be aware of:
1482             # "... method for propagating interfaces J. Comput. Phys."
1483             # next if (scalar(@Words) <= 2 and
1484 1 50 33     6 next if (scalar(@Words) <= 2 and $Parts[$i-1] !~ /^\d/);
1485              
1486 1 50 33     5 if (scalar(@Words) <= 4 and
1487             $Parts[$i-1] =~ /^([A-Z][a-z]*\s+){0,3}[A-Z][a-z]*$/){
1488             next
1489 0         0 };
1490            
1491 1         3 my $w = pop(@Words);
1492             # if ($w =~ /^[A-Z]$/ or $w =~ /^[A-Z][a-z]+$/) {
1493             # if ($w =~ /^J$/ or $w =~ /^[A-Z][a-z]+$/) {
1494 1 50       4 if ($w =~ /^J$/){
1495 0         0 push(@Title_words, $w)
1496             };
1497              
1498             last
1499 1         2 };
1500 1 50       5 if (scalar(@Title_words) == 1) {
1501 1         3 $cite->{'title'} = $Title_words[0]
1502             }
1503             else {
1504 0         0 my @Title_words_real = reverse(@Title_words);
1505 0         0 $cite->{'title'} = join('.', @Title_words_real);
1506             };
1507              
1508 1 50       4 $cite->{'title'} = "$cite->{'title'}\." if ($end_dot == 1);
1509            
1510             # normalise it
1511 1         7 $cite->{'title'} = normalise_journal($cite->{'title'});
1512 1         4 return 1
1513             };
1514            
1515              
1516              
1517             sub full_name {
1518 2     2 0 4 my $Text = shift;
1519              
1520 2         19 $Text =~ s/(^|s*)Jr[. ]//i;
1521              
1522 2 50       16 return 1 if ($Text =~ /^\s*et al\s*$/i);
1523              
1524 2 50       8 return 0 if ($Text =~/^in /i);
1525 2 50       8 return 0 if ($Text !~ /[A-Z]/); # no upper case letter
1526 2 50       8 return 0 if ($Text =~ /\d+/); # $Text contains title.
1527 2 50       6 return 0 if ($Text =~ / (e-print|archive)s? /i);
1528 2 50       7 return 0 if ($Text =~ /\b(Collaboration|Review)\b/i);
1529              
1530 2         5 my $wCount = word_count($Text);
1531 2 50       7 return 0 if $wCount > 4;
1532              
1533             # "van Albada" or "van den Bergh" (surname only)
1534 2 50       8 return 0 if ($Text =~ /^((v\.|von|van|de|den|der)\s+)+\S\S+\s*$/i);
1535             # "van Buren D"
1536 2 50       5 return 1 if ($Text =~ /^(von|van|de|den|der)\s+\S\S+\s+([a-z]+\s*)+$/i);
1537             # (journal name)
1538 2 50       7 return 0 if ($Text =~ /\b(Phy\.|Physics|Journal|The)\b/i);
1539             # "J. Mod. Phys. D"; "Prog.Theor.Phys."
1540 2 50       7 return 0 if ($Text =~ /^([a-z]+\.\s*)+[a-z]?\s*$/i);
1541             # "Phys Rev A"
1542             # return 0 if ($Text =~ /^([a-z][a-z]+(\.| )){2,}[a-z]\.?\s*$/i);
1543 2         8 my @Abbr = ();
1544             # "Class. Quantum Grav."
1545 2 50 33     9 return 0 if (@Abbr = ($Text =~ /\S\S+?\./g) and
1546             scalar(@Abbr) >1);
1547             # "Nuovo Cim. B 44, 1 (1966)."
1548 2 50       6 return 0 if ($Text =~ /\w\w\w+\./);
1549            
1550             # 'W. B. Burton', 'Burton W. B.', 'W B Burton', etc.
1551 2 0 33     7 if (has_surname($Text) and
      33        
      0        
1552             has_initials($Text) and
1553             $wCount >= 1 and
1554             $wCount < 5 ) {
1555 0         0 return 1
1556             };
1557              
1558             # 'Vivek Agrawal', 'Liu Xin' types; hard to distinguish
1559             # surname/firstname.
1560 2 0 33     9 if ($wCount >= 2 and
      33        
1561             $wCount <= 3 and
1562             no_initials($Text)) {
1563 0         0 return 1
1564             };
1565              
1566 2         9 return 0
1567             };
1568            
1569             sub no_initials {
1570 0     0 0 0 my $Text = shift;
1571              
1572             # do not count 'Jr.'
1573 0         0 $Text =~ s/(\W)Jr\.?\s*$/$1/i;
1574 0 0       0 return 0 if ($Text =~ /(^| )[a-z]\./i);
1575 0 0       0 return 0 if ($Text =~ /(^| )[a-z]( |$)/i);
1576              
1577 0         0 return 1;
1578             };
1579              
1580             sub only_initials {
1581 1     1 0 3 my $Text = shift;
1582              
1583 1 50       6 return 0 if ($Text =~ /^[a-z]{2,} /i);
1584 1 50       25 return 0 if ($Text =~ /\.?\s*[a-z][a-z]+$/i);
1585              
1586 0         0 my @Words = split(/[\.\s]/, $Text);
1587 0         0 my $Word;
1588 0 0       0 foreach $Word (@Words) { return 0 if (length($Word) >= 2)};
  0         0  
1589            
1590 0         0 return 1
1591             };
1592              
1593             sub is_surname {
1594 1     1 0 2 my ($Text) = @_;
1595 1         3 $Text =~ s/ Jr\W+$//i;
1596              
1597 1 50       4 return 0 if ($Text =~ / (e-print|archive)s? /i);
1598 1 50       4 return 0 if ($Text =~ /\bCollaboration\b/i);
1599              
1600 1 50       13 return 1 if ($Text =~ /^(\s*[a-z][\-'a-z]+){1,3}$/i);
1601             # return 1 if ($Text =~ /^\s*[a-z]+[\-'a-z]+\s*$/i);
1602              
1603 0         0 return 0
1604             }
1605              
1606             sub has_surname {
1607 2     2 0 3 my $Text = shift;
1608              
1609 2 50       8 return 0 if ($Text =~ /\d+/);
1610 2 50       8 return 1 if ($Text =~ /^[a-z]{2,}[\s\-']/i);
1611             # return 1 if ($Text =~ /[a-z]{2,}$/i);
1612 2 50       7 return 1 if ($Text =~ /[\-'\s.][a-z][a-z]+(\s+Jr\.?)?\s*$/i);
1613 2         8 return 0
1614             }
1615              
1616             sub has_initials {
1617 1     1 0 2 my $Text = shift;
1618              
1619 1 50       4 return 0 if ($Text =~ /\d+/);
1620 1 50       10 return 1 if ($Text =~ /^\s*[']?\s*[A-Z](\s|\.|$)/);
1621 0 0       0 return 1 if ($Text =~ /(^|\s|\.)[a-z](\s|\.|$)/i);
1622            
1623 0         0 return 0
1624             }
1625              
1626             # mainly used to count 'words' in author names
1627             sub word_count {
1628 4     4 0 8 my ($Text) = @_;
1629              
1630             #$Text =~ s/^[\s.]+//;
1631             #my @Words = split(/[\s.]+/, $Text);
1632             # return scalar(@Words);
1633              
1634 4         7 $Text =~ s/ (von|van|de|den|der) //g;
1635 4         7 $Text =~ s/^\s+//;
1636 4         10 $Text =~ s/\s+$//;
1637 4         13 my @Words_all = split(/\s+/, $Text);
1638             # ignore initials in names.
1639             # e.g. "C.A.R. Sa de Melo" is a name
1640 4         5 my @Words;
1641             my $W;
1642 4         12 while (@Words_all) {
1643 5         7 $W = shift @Words_all;
1644 5 100       29 push(@Words, $W) if ($W !~ /^[a-z]\.?$/i);
1645             };
1646 4         15 return scalar(@Words);
1647             };
1648            
1649             1;
1650              
1651             __END__