File Coverage

blib/lib/Lingua/JA/FindDates.pm
Criterion Covered Total %
statement 198 228 86.8
branch 118 148 79.7
condition 28 57 49.1
subroutine 15 17 88.2
pod 9 11 81.8
total 368 461 79.8


line stmt bran cond sub pod time code
1             package Lingua::JA::FindDates;
2 4     4   239128 use warnings;
  4         31  
  4         127  
3 4     4   21 use strict;
  4         6  
  4         200  
4 4     4   29 use Carp qw/carp croak cluck/;
  4         16  
  4         282  
5 4     4   1043 use utf8;
  4         29  
  4         19  
6 4     4   1054 use 5.010000;
  4         28  
7              
8             require Exporter;
9             our @ISA = qw(Exporter);
10             our @EXPORT_OK= qw/subsjdate kanji2number seireki_to_nengo nengo_to_seireki
11             regjnums @jdatere $jera %jera2w/;
12             our %EXPORT_TAGS = (
13             all => \@EXPORT_OK,
14             );
15              
16             our $VERSION = '0.028';
17              
18             # Kanji number conversion table.
19              
20             my %kanjinums =
21             (
22             〇 => 0,
23             一 => 1,
24             二 => 2,
25             三 => 3,
26             四 => 4,
27             五 => 5,
28             六 => 6,
29             七 => 7,
30             八 => 8,
31             九 => 9,
32             十 => 10,
33             百 => 100,
34             # Dates shouldn't get any bigger than the following times a digit.
35             千 => 1000,
36             );
37              
38             # The kanji digits.
39              
40             my $kanjidigits = join ('', keys %kanjinums);
41              
42             sub kanji2number
43             {
44 56     56 1 14470 my ($knum) = @_;
45             # Special case of 元日 (ganjitsu), 元年 (gannen), etc.
46 56 100       138 if ($knum eq '元') {
47 1         5 return 1;
48             }
49 55         161 my @kanjis = split '', $knum;
50 55         89 my $value = 0;
51 55         76 my $keta = 1;
52 55         80 while (1) {
53 135         207 my $k = pop @kanjis;
54 135 100       261 if (! defined $k) {
55 48         173 return $value;
56             }
57 87         207 my $val = $kanjinums{$k};
58             # Make sure this kanji is one we know
59 87 100       157 if (! defined $val) {
60 1         14 warn "can't cope with '$k' of input '$knum'";
61 1         9 return 0;
62             }
63             # If the value of the individual kanji is 10 or more.
64 86 100       164 if ($val >= 10) {
65 30         47 $keta = $val;
66 30         42 my $knext = pop @kanjis;
67 30 100       63 if (!$knext) {
68 5         24 return $value + $val;
69             }
70 25         49 my $val_next = $kanjinums{$knext};
71 25 100       56 if (! defined $val_next) {
72             # Kanji is not a numerical one we know of.
73 1         18 warn "can't cope with '$knext' of input '$knum'.\n";
74 1         16 return 0;
75             }
76             # If we have a hundred followed by a thousand, without a
77             # three, four, etc., like "千百".
78 24 100       59 if ($val_next > 10) {
79             # Put it back on the stack
80 2         5 push @kanjis, $knext;
81             # $value += 1*$val, since the digit for $val is
82             # defaulted to one.
83 2         4 $value += $val;
84             }
85             else {
86 22         41 $value += $val_next * $val;
87             }
88             }
89             else {
90             # $k is a kanji digit from 0 to 9, and $val is its value,
91             # as if 一二三 or something, without tens, hundreds,
92             # thousands, etc.
93 56         100 $value += $val * $keta;
94 56         82 $keta *= 10;
95             }
96             }
97             }
98              
99             # ____
100             # | _ \ ___ __ _ _____ _____ ___
101             # | |_) / _ \/ _` |/ _ \ \/ / _ \/ __|
102             # | _ < __/ (_| | __/> < __/\__ \
103             # |_| \_\___|\__, |\___/_/\_\___||___/
104             # |___/
105              
106             my $jdigit = qr/[0-90-9]/;
107              
108             # A regular expression to match Japanese numbers
109              
110             my $jnumber = qr/($jdigit+|[$kanjidigits]+)/x;
111              
112             # A regular expression to match a Western year
113              
114             my $wyear = qr/
115             (
116             $jdigit{4}
117             |
118             [$kanjidigits]?千[$kanjidigits]*
119             |
120             [\']$jdigit{2}
121             )
122             \s*年
123             /x;
124              
125             my $alpha_era = qr/
126             # If the H, S, T, or M is part of a longer
127             # string of romaji, do not match it.
128             (?
129             (?:
130             [H|H|S|S|T|T|M|M]
131             )
132 4     4   28 /xi;
  4         7  
  4         42  
133              
134             # The recent era names (Heisei, Showa, Taisho, Meiji). These eras are
135             # sometimes written using the letters H, S, T, and M.
136              
137             our $jera = qr/($alpha_era|平|昭|大|明|平成|昭和|大正|明治|㍻|㍼|㍽|㍾)/;
138              
139             # A map of Japanese eras to Western dates. These are the starting year
140             # of the period minus one, to allow for that the first year is "heisei
141             # one" rather than "heisei zero".
142              
143             our %jera2w = (
144             H => 1988,
145             H => 1988,
146             平成 => 1988,
147             平 => 1988,
148             '㍻' => 1988,
149             S => 1925,
150             S => 1925,
151             昭和 => 1925,
152             昭 => 1925,
153             '㍼' => 1925,
154             T => 1911,
155             T => 1911,
156             大正 => 1911,
157             大 => 1911,
158             '㍽' => 1911,
159             M => 1867,
160             M => 1867,
161             明治 => 1867,
162             明 => 1867,
163             '㍾' => 1867,
164             );
165              
166             # Japanese year, with era like "Heisei" at the beginning.
167              
168             my $jyear = qr/
169             $jera
170             \h*
171             # Only match up to one or two of these digits, to
172             # prevent unlikely matches.
173             (
174             $jdigit{1,2}
175             |
176             [$kanjidigits]{1,2}
177             |
178             # The first year of an era, something like
179             # "昭和元年" (1926, the first year of the Showa era).
180            
181             )
182             \h*
183            
184             /x;
185              
186             # The "jun" or approximately ten day periods (thirds of a month)
187              
188             my %jun = qw/初 1 上 1 中 2 下 3/;
189              
190             # The translations of the "jun" above into English.
191              
192             my @jun2english = (
193             'invalid',
194             'early ',
195             'mid-',
196             'late ',
197             );
198              
199             # Japanese days of the week, from Monday to Sunday.
200              
201             my $weekdays = '月火水木金土日';
202             my @weekdays = split '',$weekdays;
203              
204             # Match a string for a weekday, like 月曜日 or (日)
205             # The long part (?=\W) is to stop it from accidentally matching a
206             # kanji which is part of a different word, like the following:
207             #平成二十年七月一日
208             # 日本論・日本人論は非常に面白いものだ。
209              
210             my $match_weekday =
211             qr/[\((]?
212             ([$weekdays])
213             (?:(?:(?:曜日|曜)[)\)])|[)\)]|(?=\W))
214             /x;
215              
216             # Match a day of the month, like 10日
217              
218             my $match_dom = qr/$jnumber\h*日/;
219              
220             # Match a month
221              
222             my $match_month = qr/$jnumber\h*月/;
223              
224             # Match a "jun" (a third of a month).
225              
226             my $jun_keys = join ('', keys %jun);
227              
228             my $match_jun = qr/([$jun_keys])\h*旬/;
229              
230             # Match a month+jun
231              
232             my $match_month_jun = qr/$match_month\h*$match_jun/;
233              
234             # Match a month and day of month pair
235              
236             my $match_month_day = qr/$match_month\h*$match_dom/;
237              
238             # Match a Japanese year, month, day string
239              
240             my $matchymd = qr/
241             $jyear
242             \h*
243             $match_month_day
244             /x;
245              
246             # Match a Western year, month, day string
247              
248             my $matchwymd = qr/$wyear\h*$match_month_day/;
249              
250             # Match a Japanese year and month only
251              
252             my $match_jyear_month = qr/$jyear\h*$match_month/;
253              
254             # Match a Western year and month only
255              
256             my $match_wyear_month = qr/$wyear\h*$match_month/;
257              
258             # Match a month, day, weekday.
259              
260             my $match_month_day_weekday = qr/$match_month_day\h*$match_weekday/;
261              
262             # Separators used in date strings
263             # Microsoft Word uses Unicode 0xFF5E, the "fullwidth tilde", for nyoro symbol.
264              
265             my $separators = qr/\h*[〜−~]\h*/;
266            
267             # _ _ _ __
268             # | | (_)___| |_ ___ / _| _ __ ___ __ _ _____ _____ ___
269             # | | | / __| __| / _ \| |_ | '__/ _ \/ _` |/ _ \ \/ / _ \/ __|
270             # | |___| \__ \ |_ | (_) | _| | | | __/ (_| | __/> < __/\__ \
271             # |_____|_|___/\__| \___/|_| |_| \___|\__, |\___/_/\_\___||___/
272             # |___/
273              
274             # This a list of date regular expressions.
275              
276             our @jdatere = (
277              
278             # Match an empty string like 平成 月 日 as found on a form etc.
279              
280             [qr/
281             $jyear
282             (\h+)
283            
284             \h+
285            
286             /x,
287             "ejx"],
288              
289             # Add match for dummy strings here!
290              
291             # Match a Japanese era, year, 2 x (month day weekday) combination
292              
293             [qr/
294             $matchymd
295             \h*$match_weekday
296             $separators
297             $matchymd
298             \h*$match_weekday
299             /x,
300             "e1j1m1d1w1e2j2m2d2w2"],
301              
302             # Match 2 x (era, year, month, day) combination
303              
304             [qr/
305             $matchymd
306             $separators
307             $matchymd
308             /x,
309             "e1j1m1d1e2j2m2d2"],
310              
311             # Match a Japanese era, year, month 2 x (day, weekday) combination
312              
313             [qr/
314             $matchymd
315             $match_weekday
316             $separators
317             $match_dom
318             \h*
319             $match_weekday
320             /x,
321             "ejmd1w1d2w2"],
322              
323             # Match a Japanese era, year, month 2 x day combination
324              
325             [qr/
326             $matchymd
327             $separators
328             $match_dom
329             \h*
330             $match_weekday
331             /x,
332             "ejmd1d2"],
333              
334             # Match 2x(Western year, month, day, weekday) combination
335              
336             [qr/
337             $matchwymd
338             \h*
339             $match_weekday
340             $separators
341             $matchwymd
342             $match_weekday
343             /x,
344             "y1m1d1w1y2m2d2w2"],
345              
346             # Match a Western year, 2x(month, day, weekday) combination
347              
348             [qr/
349             $matchwymd
350             \h*
351             $match_weekday
352             $separators
353             $match_month_day_weekday
354             /x,
355             "ym1d1w1m2d2w2"],
356              
357             # Match a Western year, month, 2x(day, weekday) combination
358              
359             [qr/
360             $matchwymd
361             \h*
362             $match_weekday
363             $separators
364             $match_dom
365             \h*
366             $match_weekday
367             /x,
368             "ymd1w1d2w2"],
369              
370             # Match a Western year, month, 2x(day) combination
371              
372             [qr/
373             $matchwymd
374             $separators
375             $match_dom
376             /x,
377             "ymd1d2"],
378              
379             # Match a Japanese era, year, month1 day1 - month 2 day2 combination
380              
381             [qr/
382             $matchymd
383             $separators
384             $match_month_day
385             /x,
386             "ejm1d1m2d2"],
387              
388             # Match 2 x ( Japanese era, year, month) combination
389              
390             [qr/
391             $jyear
392             \h*
393             $jnumber
394             \h*月?
395             $separators
396             $jyear
397             \h*
398             $match_month
399             /x, "e1j1m1e2j2m2"],
400              
401             # Match a Japanese era, year, month1 - month 2 combination
402              
403             [qr/
404             $jyear
405             \h*
406             $jnumber
407             \h*月?
408             $separators
409             $match_month
410             /x, "ejm1m2"],
411              
412             # Match a Japanese era, year, month, day1 - day2 combination
413              
414             [qr/
415             $match_jyear_month
416             \h*
417             $jnumber
418             \h*日?
419             $separators
420             $match_dom
421             /x,
422             "ejmd1d2"],
423              
424             # Match a Japanese era, year, month, day, weekday combination
425              
426             [qr/
427             $matchymd
428             \h*
429             $match_weekday
430             /x,
431             "ejmdw"],
432              
433             # Match a Japanese era, year, month, day
434              
435             [qr/$matchymd/,
436             "ejmd"],
437              
438             # Match a Japanese era, year, month, jun
439              
440             [qr/
441             $match_jyear_month
442             \h*
443             $match_jun
444             /x,
445             "ejmz"],
446              
447             # Match a Western year, month, day, weekday combination
448              
449             [qr/
450             $matchwymd
451             \h*
452             $match_weekday
453             /x,
454             "ymdw"],
455              
456             # Match a Western year, month, day combination
457              
458             [qr/$matchwymd/,
459             "ymd"],
460              
461             # Match a Western year, month, jun combination
462              
463             [qr/
464             $match_wyear_month
465             \h*
466             $match_jun
467             /x,
468             "ymz"],
469              
470             # Match a Japanese era, year, month
471              
472             [qr/
473             $jyear
474             \h*
475             $jnumber
476             \h*
477            
478             /x,
479             "ejm"],
480              
481             # Match a Western year, month
482              
483             [qr/$match_wyear_month/,
484             "ym"],
485              
486             # Match 2 x (month, day, weekday)
487              
488             [qr/
489             $match_month_day_weekday
490             $separators
491             $match_month_day_weekday
492             /x,
493             "m1d1w1m2d2w2"],
494              
495             # Match month, 2 x (day, weekday)
496              
497             [qr/
498             $match_month_day_weekday
499             $separators
500             $match_dom
501             \h*
502             $match_weekday
503             /x,
504             "md1w1d2w2"],
505              
506             # Match month, 2 x (day, weekday)
507              
508             [qr/
509             $match_month_day
510             $separators
511             $match_dom
512             /x,
513             "md1d2"],
514              
515             # Match a month, day, weekday
516              
517             [qr/$match_month_day_weekday/,
518             "mdw"],
519              
520             # Match a month, day
521              
522             [qr/$match_month_day/,
523             "md"],
524              
525             # Match a fiscal year (年度, nendo in Japanese). These usually don't
526             # have months combined with them, so there is nothing to match a
527             # fiscal year with a month.
528              
529             [qr/
530             $jyear
531            
532             /x,
533             "en"],
534              
535             # Match a fiscal year (年度, nendo in Japanese). These usually don't
536             # have months combined with them, so there is nothing to match a
537             # fiscal year with a month.
538              
539             [qr/
540             $wyear
541            
542             /x,
543             "n"],
544              
545             # Match a Japanese era, year
546              
547             [qr/$jyear/,
548             "ej"],
549              
550             # Match a Western year
551              
552             [qr/$wyear/,
553             "y"],
554              
555             # Match a month with a jun
556              
557             [
558             qr/
559             $match_month
560             \h*
561             $match_jun
562             /x,
563             "mz"
564             ],
565              
566             # Match a month
567              
568             [
569             qr/$match_month/,
570             "m"
571             ],
572             );
573              
574             my @months = qw/Invalid
575             January
576             February
577             March
578             April
579             May
580             June
581             July
582             August
583             September
584             October
585             November
586             December
587             MM/;
588              
589             my @days = qw/Invalid
590             Monday
591             Tuesday
592             Wednesday
593             Thursday
594             Friday
595             Saturday
596             Sunday/;
597              
598             # This is a translation table from the Japanese weekday names to the
599             # English ones.
600              
601             my %j2eweekday;
602              
603             @j2eweekday{@weekdays} = (1..7);
604              
605             # This is the default routine for turning a Japanese date into a
606             # foreign-style one.
607              
608             sub make_date
609             {
610 0     0 1 0 goto & default_make_date;
611             }
612              
613             sub make_date_interval
614             {
615 0     0 1 0 goto & default_make_date_interval;
616             }
617              
618             sub default_make_date
619             {
620 46     46 1 90 my ($datehash) = @_;
621             my ($year, $month, $date, $wday, $jun) =
622 46         96 @{$datehash}{qw/year month date wday jun/};
  46         178  
623 46 0 66     129 if (!$year && !$month && !$date && !$jun) {
      33        
      0        
624 0         0 carp "No valid inputs\n";
625 0         0 return;
626             }
627 46         101 my $edate = '';
628 46 100       119 $edate = $days[$wday].", " if $wday;
629 46 100       88 if ($month) {
630 34         72 $month = int ($month); # In case it is 07 etc.
631 34         80 $edate .= $months[$month];
632 34 100       74 if ($jun) {
633 1         4 $edate = $jun2english[$jun] . $edate;
634             }
635             }
636 46 100       111 if ($date) {
    100          
637 29 50       75 $edate .= " " if length ($edate);
638 29         51 $date = int ($date); # In case it is 07 etc.
639 29 100       56 $date = "DD" if $date == 32;
640 29 100       45 if ($year) {
641 25         67 $edate .= "$date, $year";
642             }
643             else {
644 4         12 $edate .= "$date";
645             }
646             }
647             elsif ($year) {
648 14 100       42 if (length ($edate) > 0) {
649 2         2 $edate .= " ";
650             }
651 14         31 $edate .= $year;
652             }
653 46         102 return $edate;
654             }
655              
656             our $date_sep = '-';
657              
658             # This is the default routine for turning a date interval into a
659             # foreign-style one, which is then substituted into the text.
660              
661             sub default_make_date_interval
662             {
663 17     17 1 850 my ($date1, $date2) = @_;
664 17         38 my $einterval = '';
665 17         25 my $usecomma;
666             # The case of an interval with different years doesn't need to be
667             # considered, because each date in that case can be considered a
668             # single date.
669              
670 17 100       52 if ($date2->{month}) {
671 9 50       60 if (!$date1->{month}) {
672 0         0 carp "end month but no starting month";
673 0         0 return;
674             }
675             }
676 17 50       48 if ($date1->{month}) {
677 17 100 66     91 if ($date1->{wday} && $date2->{wday}) {
    100 66        
678 6 50 33     32 if (! $date1->{date} || ! $date2->{date}) {
679 0         0 carp "malformed date has weekdays but not days of month";
680 0         0 return;
681             }
682 6         10 $usecomma = 1;
683             $einterval = $days[$date1->{wday}] . " " . $date1->{date} .
684             ($date2->{month} ? ' '.$months[int ($date1->{month})] : ''). $date_sep .
685             $days[$date2->{wday}] . " " . $date2->{date} . " " .
686 6 100       75 ($date2->{month} ? $months[int ($date2->{month})] : $months[int ($date1->{month})]);
    100          
687             }
688             elsif ($date1->{date} && $date2->{date}) {
689 7         12 $usecomma = 1;
690 7 50 33     32 if ($date1->{wday} || $date2->{wday}) {
691 0         0 carp "malformed date interval: ",
692             "has weekday for one date $date1->{wday} but not the other one $date2->{wday} .";
693 0         0 return;
694             }
695             $einterval = $months[int ($date1->{month})] . ' ' .
696             $date1->{date} . $date_sep .
697             ($date2->{month} ?
698             $months[int ($date2->{month})] . ' ' : '') .
699 7 100       58 $date2->{date};
700             }
701             else { # no dates or weekdays
702 4 50 33     20 if ($date1->{date} || $date2->{date}) {
703 0         0 cluck "malformed date interval: only one day of month";
704 0         0 return;
705             }
706 4 50       12 if (!$date2->{month}) {
707 0         0 carp "start month but no end month or date";
708 0         0 return;
709             }
710             $einterval = $months[int($date1->{month})] . $date_sep .
711 4         25 $months[int($date2->{month})] .
712             $einterval;
713             }
714             }
715             else { # weekday - day / weekday - day case.
716 0 0 0     0 if ($date1->{wday} && $date2->{wday}) {
717 0 0 0     0 if (! $date1->{date} || ! $date2->{date}) {
718 0         0 carp "malformed date has weekdays but not days of month";
719 0         0 return;
720             }
721             $einterval = $date1->{wday} . " " . $date1->{date} . $date_sep .
722 0         0 $date2->{wday} . " " . $date2->{date};
723             }
724             }
725 17 100       65 if ($date1->{year}) {
726 16 100       56 my $year1 = ($usecomma ? ', ': ' ').$date1->{year};
727 16 100 66     61 if (! $date2->{year} || $date2->{year} == $date1->{year}) {
728 14         37 $einterval .= $year1;
729             }
730             else {
731 2         23 $einterval =~ s/\Q$date_sep/$year1$date_sep/;
732 2 50       10 my $year2 = ($usecomma ? ', ': ' ').$date2->{year};
733 2         7 $einterval .= $year2;
734             }
735             }
736 17         60 return $einterval;
737             }
738              
739             our $verbose = 0;
740              
741             sub subsjdate
742             {
743             # $text is the text to substitute. It needs to be in Perl's
744             # internal encoding.
745             # $replace_callback is a routine to call back if we find valid dates.
746             # $data is arbitrary data to pass to the callback routine.
747 56     56 1 71406 my ($text, $c) = @_;
748             # Save doing existence tests.
749 56 100       220 if (! $c) {
750 49         129 $c = {};
751             }
752 56 100       159 if (! $text) {
753 2         11 return $text;
754             }
755             # Loop through all the possible regular expressions.
756 54         149 for my $datere (@jdatere) {
757 1728         22954 my $regex = $datere->[0];
758 1728         8115 my @process = split (/(?=[a-z][12]?)/, $datere->[1]);
759 1728 50       27224 if ($verbose) {
760 0         0 print "Looking for $datere->[1]\n";
761             }
762 1728         215639 while ($text =~ /($regex)/g) {
763 71         18729 my $date1;
764             my $date2;
765             # The matching string is in the following variable.
766 71         312 my $orig = $1;
767 71         574 my @matches = ($2,$3,$4,$5,$6,$7,$8,$9);
768 71 50       218 if ($verbose) {
769 0         0 print "Found '$orig': ";
770             }
771 71         964 for (0..$#matches) {
772 331         513 my $arg = $matches[$_];
773              
774 331 100       651 last if !$arg;
775 261         759 $arg =~ tr/0-9/0-9/;
776 261         1245 $arg =~ s/([$kanjidigits]+|元)/kanji2number($1)/ge;
  47         143  
777 261 50       491 if ($verbose) {
778 0         0 print "Arg $_: $arg ";
779             }
780 261         398 my $argdo = $process[$_];
781 261 100 100     1858 if ($argdo eq 'e1') { # Era name in Japanese
    100 100        
    50 100        
    100          
    100          
    50          
    100          
    100          
    100          
    100          
    100          
    100          
    100          
    100          
    100          
    100          
    100          
    50          
782 1         6 $date1->{year} = $jera2w{$arg};
783             }
784             elsif ($argdo eq 'j1') { # Japanese year
785 1         5 $date1->{year} += $arg;
786             }
787             elsif ($argdo eq 'y1') {
788 0         0 $date1->{year} = $arg;
789             }
790             elsif ($argdo eq 'e2') { # Era name in Japanese
791 1         4 $date2->{year} = $jera2w{$arg};
792             }
793             elsif ($argdo eq 'j2') { # Japanese year
794 1         4 $date2->{year} += $arg;
795             }
796             elsif ($argdo eq 'y2') {
797 0         0 $date2->{year} = $arg;
798             }
799             elsif ($argdo eq 'e') { # Era name in Japanese
800 43         198 $date1->{year} = $jera2w{$arg};
801             }
802             elsif ($argdo eq 'j') { # Japanese year
803 42         208 $date1->{year} += $arg;
804             }
805             elsif ($argdo eq 'y') {
806 18         65 $date1->{year} = $arg;
807             }
808             elsif ($argdo eq 'n') {
809 2         6 $date1->{year} += $arg;
810 2         7 $date1->{year} = "fiscal ".$date1->{year};
811             }
812             elsif ($argdo eq 'm' || $argdo eq 'm1') {
813 58         161 $date1->{month} = $arg;
814             }
815             elsif ($argdo eq 'd' || $argdo eq 'd1') {
816 49         137 $date1->{date} = $arg;
817             }
818             elsif ($argdo eq 'm2') {
819 8         25 $date2->{month} = $arg;
820             }
821             elsif ($argdo eq 'd2') {
822 12         41 $date2->{date} = $arg;
823             }
824             elsif ($argdo eq 'w' || $argdo eq 'w1') {
825 18         61 $date1->{wday} = $j2eweekday{$arg};
826             }
827             elsif ($argdo eq 'w2') {
828 5         17 $date2->{wday} = $j2eweekday{$arg};
829             }
830             elsif ($argdo eq 'z') {
831 1         5 $date1->{jun} = $jun{$arg};
832             }
833             elsif ($argdo eq 'x') {
834 1 50       4 if ($verbose) {
835 0         0 print "Dummy date '$orig'.\n";
836             }
837 1         3 $date1->{date} = 32;
838 1         3 $date1->{month} = 13;
839             }
840             }
841 71         129 my $edate;
842 71 100       141 if ($date2) {
843             # Date interval
844 16 50       42 if ($c->{make_date_interval}) {
845 0         0 $edate = &{$c->{make_date_interval}} ($c->{data}, $orig,
  0         0  
846             $date1, $date2);
847             }
848             else {
849 16         58 $edate = default_make_date_interval ($date1, $date2);
850             }
851             }
852             else {
853             # Single date
854 55 100       116 if ($c->{make_date}) {
855 9         23 $edate = &{$c->{make_date}}($c->{data}, $orig, $date1);
  9         27  
856             }
857             else {
858 46         126 $edate = default_make_date ($date1);
859             }
860             }
861 71 50       412 if ($verbose) {
862 0         0 print "-> '$edate'\n";
863             }
864 71         1066 $text =~ s/\Q$orig\E/$edate/g;
865 71 100       648 if ($c->{replace}) {
866 13         32 &{$c->{replace}} ($c->{data}, $orig, $edate);
  13         38  
867             }
868             }
869             }
870 54         778 return $text;
871             }
872              
873             sub nengo_to_seireki
874             {
875 1     1 1 10650 my ($text) = @_;
876 1         4 my %data;
877 1         3 $data{count} = 0;
878              
879 1         12 my $out_text = subsjdate (
880             $text, {
881             make_date => \& nengo_to_seireki_make_date,
882             data => \%data,
883             }
884             );
885 1         17 $out_text =~ s/#REPLACEME(\d+)REPLACEME#/$data{$1}/g;
886 1         10 return $out_text;
887             }
888              
889             sub nengo_to_seireki_make_date
890             {
891 4     4 0 9 my ($data, $original, $date) = @_;
892 4 50       8 if ($date->{year}) {
893 4         25 $original =~ s/.*年/$date->{year}年/;
894 4         7 my $count = $data->{count};
895 4         8 $data->{$count} = $original;
896 4         7 $data->{count}++;
897 4         13 return "#REPLACEME${count}REPLACEME#";
898             }
899             else {
900 0         0 return $original;
901             }
902             }
903              
904             sub seireki_to_nengo
905             {
906 2     2 1 10683 my ($text) = @_;
907 2         4 my %data;
908 2         5 $data{count} = 0;
909              
910 2         16 my $out_text = subsjdate (
911             $text, {
912             make_date => \& seireki_to_nengo_make_date,
913             data => \%data,
914             }
915             );
916 2         21 $out_text =~ s/#REPLACEME(\d+)REPLACEME#/$data{$1}/g;
917 2         17 return $out_text;
918             }
919              
920             sub seireki_to_nengo_make_date
921             {
922 2     2 0 7 my ($data, $original, $date) = @_;
923 2         3 my $year = $date->{year};
924 2         12 my @eras = (
925             ['平成', 1989, 1, 8],
926             ['昭和', 1926, 12, 25],
927             ['大正', 1912, 7, 30],
928             ['明治', 1868, 1, 25],
929             );
930 2 50       6 if (defined $year) {
931 2         5 for my $era (@eras) {
932 3         5 my $ename = $era->[0];
933 3         5 my $eyear = $era->[1];
934 3         5 my $emonth = $era->[2];
935 3         4 my $eday = $era->[3];
936 3         3 my $month = $date->{month};
937 3         5 my $date = $date->{date};
938              
939             # This is a flag which says whether to perform a
940             # substitution of the year or not.
941              
942 3         4 my $subs;
943              
944             # If the year is greater than the era year, or if the year
945             # is the same as the era year and we do not know the
946             # month, just replace.
947              
948 3 100 33     23 if ($year > $eyear ||
    50 66        
      33        
949             ($year == $eyear && ! defined ($month))) {
950 1         1 $subs = 1;
951             }
952              
953             # If the year is the same, and there is a month
954              
955             elsif ($year == $eyear && defined ($month)) {
956              
957             # If there is a day of the month, then only substitute
958             # if the month is greater than the changeover month,
959             # or the month is the same, and the day of the month
960             # is greater than or equal to the changeover day of
961             # the month.
962              
963 2 50       5 if (defined ($date)) {
    0          
964 2 100 33     12 if ($month > $emonth ||
      66        
965             ($month == $emonth && $date >= $eday)) {
966 1         1 $subs = 1;
967             }
968             }
969              
970             # If we don't know the day of the month, substitute if
971             # the month is greater than or equal to the changeover
972             # month.
973              
974             elsif ($month >= $emonth) {
975 0         0 $subs = 1;
976             }
977             }
978 3 100       8 if ($subs) {
979              
980             # Only substitute if we need to.
981              
982 2 50       22 if ($original !~ /$ename/) {
983              
984             # The year counting starts from 1, so we add 1 to
985             # the difference.
986              
987 2         5 my $hyear = $year - $eyear + 1;
988 2         19 $original =~ s/\d+年/$ename${hyear}年/;
989             }
990              
991             # Don't replace again, stop the loop.
992              
993 2         5 last;
994             }
995             }
996             }
997 2         4 my $count = $data->{count};
998 2         5 $data->{$count} = $original;
999 2         4 $data->{count}++;
1000              
1001             # This is a tag for substituting with.
1002              
1003 2         9 return "#REPLACEME${count}REPLACEME#";
1004             }
1005              
1006             # Regularize any small integer Japanese numbers in a piece of text.
1007              
1008             sub regjnums
1009             {
1010 2     2 1 570 my ($input) = @_;
1011 2         33 $input =~ tr/0-9/0-9/;
1012 2         50 $input =~ s/([$kanjidigits]+)/kanji2number($1)/ge;
  1         5  
1013 2         13 return $input;
1014             }
1015              
1016             1;
1017