line |
stmt |
bran |
cond |
sub |
pod |
time |
code |
1
|
|
|
|
|
|
|
# $Id: DateRange.pm,v 1.2 2005/04/19 15:33:02 dk Exp $ |
2
|
|
|
|
|
|
|
|
3
|
|
|
|
|
|
|
package Regexp::Log::DateRange; |
4
|
1
|
|
|
1
|
|
919
|
use strict; |
|
1
|
|
|
|
|
1
|
|
|
1
|
|
|
|
|
35
|
|
5
|
1
|
|
|
1
|
|
7
|
use vars qw($VERSION %templates); |
|
1
|
|
|
|
|
1
|
|
|
1
|
|
|
|
|
1386
|
|
6
|
|
|
|
|
|
|
|
7
|
|
|
|
|
|
|
$VERSION = '0.02'; |
8
|
|
|
|
|
|
|
|
9
|
|
|
|
|
|
|
%templates = ( |
10
|
|
|
|
|
|
|
syslog => [ |
11
|
|
|
|
|
|
|
[ '\\s+', 1, 12, [ qw(. jan feb mar apr may jun jul aug sep oct nov dec)]], |
12
|
|
|
|
|
|
|
[ '\\s+', 1, 31, undef, '0?'], |
13
|
|
|
|
|
|
|
[ '\\:', 0, 23, undef, '0?' ], |
14
|
|
|
|
|
|
|
[ '\\:', 0, 59, undef, '0?' ], |
15
|
|
|
|
|
|
|
], |
16
|
|
|
|
|
|
|
); |
17
|
|
|
|
|
|
|
|
18
|
|
|
|
|
|
|
sub new |
19
|
|
|
|
|
|
|
{ |
20
|
200
|
|
|
200
|
0
|
10897864
|
my ( $class, $template, $date1, $date2) = @_; |
21
|
|
|
|
|
|
|
|
22
|
200
|
50
|
|
|
|
1132
|
unless ( ref($template)) { |
23
|
200
|
50
|
|
|
|
1066
|
die "Template '$template' doesn't exist\n" |
24
|
|
|
|
|
|
|
unless $templates{$template}; |
25
|
200
|
|
|
|
|
478
|
$template = $templates{$template}; |
26
|
|
|
|
|
|
|
} |
27
|
|
|
|
|
|
|
|
28
|
|
|
|
|
|
|
# some sanity checks |
29
|
200
|
|
|
|
|
407
|
my $n = @$template; |
30
|
200
|
50
|
|
|
|
716
|
die "template is empty\n" unless $n; |
31
|
200
|
50
|
|
|
|
615
|
die "date [@$date1] is not valid\n" unless $n == @$date1; |
32
|
200
|
50
|
|
|
|
609
|
die "date [@$date2] is not valid\n" unless $n == @$date2; |
33
|
|
|
|
|
|
|
|
34
|
200
|
|
|
|
|
866
|
for ( my $i = 0; $i < $n; $i++) { |
35
|
217
|
100
|
|
|
|
703
|
next if $date1->[$i] == $date2->[$i]; |
36
|
200
|
50
|
|
|
|
800
|
last if $date1->[$i] < $date2->[$i]; |
37
|
0
|
|
|
|
|
0
|
( $date2, $date1) = ( $date1, $date2); |
38
|
0
|
|
|
|
|
0
|
last; |
39
|
|
|
|
|
|
|
} |
40
|
|
|
|
|
|
|
|
41
|
|
|
|
|
|
|
# build 'alignment' vectors; for example, for the right range, |
42
|
|
|
|
|
|
|
# 2499 would give 0111, for the left, 1150 would give 0001 |
43
|
200
|
|
|
|
|
295
|
my ( @w1, @w2); |
44
|
200
|
|
|
|
|
531
|
my ( $last1, $last2) = ( 1, 1); |
45
|
200
|
|
|
|
|
879
|
for ( my $i = $#$date1; $i > 0; $i--) { |
46
|
600
|
100
|
|
|
|
2261
|
$w1[$i-1] = $last1 & (( $date1->[$i] == $template->[$i]->[1] ) ? 1 : 0); |
47
|
600
|
100
|
|
|
|
1842
|
$w2[$i-1] = $last2 & (( $date2->[$i] == $template->[$i]->[2] ) ? 1 : 0); |
48
|
600
|
|
|
|
|
920
|
$last1 = $w1[$i-1]; |
49
|
600
|
|
|
|
|
1463
|
$last2 = $w2[$i-1]; |
50
|
|
|
|
|
|
|
} |
51
|
200
|
|
|
|
|
1156
|
my $tree = range2tree( $template, $date1, $date2, \@w1, \@w2, 0); |
52
|
200
|
|
|
|
|
780
|
return tree2re( $template, $tree, 0); |
53
|
|
|
|
|
|
|
} |
54
|
|
|
|
|
|
|
|
55
|
|
|
|
|
|
|
# 1,2,3 => (?:1|2|3) |
56
|
|
|
|
|
|
|
sub re_group |
57
|
|
|
|
|
|
|
{ |
58
|
1959
|
50
|
|
1959
|
0
|
4953
|
if ( 0 == @_) { |
|
|
100
|
|
|
|
|
|
59
|
0
|
|
|
|
|
0
|
return ''; |
60
|
|
|
|
|
|
|
} elsif ( 1 == @_) { |
61
|
775
|
|
|
|
|
2414
|
return $_[0]; |
62
|
|
|
|
|
|
|
} else { |
63
|
1184
|
|
|
|
|
11224
|
return '(?:'.join('|', @_).')'; |
64
|
|
|
|
|
|
|
} |
65
|
|
|
|
|
|
|
} |
66
|
|
|
|
|
|
|
|
67
|
|
|
|
|
|
|
# 8 .. 13 => (?:0?8|9)|1[0123] |
68
|
|
|
|
|
|
|
sub match_range |
69
|
|
|
|
|
|
|
{ |
70
|
981
|
|
|
981
|
0
|
2250
|
my ( $from, $to, $digit_prefix) = @_; |
71
|
|
|
|
|
|
|
|
72
|
981
|
|
|
|
|
1053
|
my @tens; |
73
|
981
|
|
|
|
|
1897
|
for my $x ( $from .. $to) { |
74
|
11702
|
|
|
|
|
14944
|
my $ten = int( $x / 10); |
75
|
11702
|
100
|
|
|
|
19367
|
unless ( defined $tens[$ten]) { |
76
|
1931
|
|
|
|
|
2702
|
my $mod = int( $x % 10); |
77
|
1931
|
|
|
|
|
5702
|
$tens[$ten] = [ $mod, $mod]; |
78
|
|
|
|
|
|
|
} else { |
79
|
9771
|
|
|
|
|
14833
|
$tens[$ten]->[1]++; |
80
|
|
|
|
|
|
|
} |
81
|
|
|
|
|
|
|
} |
82
|
|
|
|
|
|
|
|
83
|
981
|
|
|
|
|
1482
|
my @q; |
84
|
981
|
|
|
|
|
1284
|
my $last_range = ''; |
85
|
981
|
|
|
|
|
1138
|
my @branges; |
86
|
981
|
|
|
|
|
2834
|
for ( my $i = 0; $i < @tens; $i++) { |
87
|
2780
|
100
|
|
|
|
7076
|
next unless defined $tens[$i]; |
88
|
1931
|
100
|
|
|
|
6818
|
my $range = ( $tens[$i]->[0] == $tens[$i]->[1] ) ? |
89
|
|
|
|
|
|
|
$tens[$i]->[0] : |
90
|
|
|
|
|
|
|
"[$tens[$i]->[0]-$tens[$i]->[1]]"; |
91
|
1931
|
100
|
|
|
|
8970
|
if ( $i) { |
92
|
1439
|
100
|
|
|
|
2744
|
if ( $range eq $last_range) { |
93
|
306
|
|
|
|
|
624
|
push @branges, $i; |
94
|
306
|
|
|
|
|
1367
|
$q[-1] = "[$branges[0]-$branges[-1]]$range"; |
95
|
|
|
|
|
|
|
} else { |
96
|
1133
|
|
|
|
|
1407
|
$last_range = $range; |
97
|
1133
|
|
|
|
|
2026
|
push @q, "$i$range"; |
98
|
1133
|
|
|
|
|
4128
|
@branges = ($i); |
99
|
|
|
|
|
|
|
} |
100
|
|
|
|
|
|
|
} else { |
101
|
492
|
|
|
|
|
1829
|
push @q, "$digit_prefix$range"; |
102
|
|
|
|
|
|
|
} |
103
|
|
|
|
|
|
|
} |
104
|
|
|
|
|
|
|
|
105
|
|
|
|
|
|
|
|
106
|
981
|
|
|
|
|
2123
|
my $ret = re_group(@q); |
107
|
981
|
|
|
|
|
2906
|
$ret =~ s/\[0-9\]/\\d/g; |
108
|
981
|
|
|
|
|
4670
|
return $ret; |
109
|
|
|
|
|
|
|
} |
110
|
|
|
|
|
|
|
|
111
|
|
|
|
|
|
|
# Convert date range into a max-3-branch tree, where each branch is an alternative |
112
|
|
|
|
|
|
|
# expansion rule, and is either a range or a value leaf; the value leaves can |
113
|
|
|
|
|
|
|
# point deeper. For example, if matching date range 1 Apr - 3 June, the corresponding |
114
|
|
|
|
|
|
|
# structure would be something like |
115
|
|
|
|
|
|
|
# |
116
|
|
|
|
|
|
|
# range (Apr-May) |
117
|
|
|
|
|
|
|
# value (June, |
118
|
|
|
|
|
|
|
# range(1-3) |
119
|
|
|
|
|
|
|
# ) |
120
|
|
|
|
|
|
|
# |
121
|
|
|
|
|
|
|
sub range2tree |
122
|
|
|
|
|
|
|
{ |
123
|
795
|
|
|
795
|
0
|
1398
|
my ( $template, $d1, $d2, $w1, $w2, $depth) = @_; |
124
|
|
|
|
|
|
|
|
125
|
795
|
|
|
|
|
1139
|
my ( $i, $left, $center, $right); |
126
|
795
|
|
|
|
|
1494
|
my ( $r1, $r2) = ( $d1-> [$depth], $d2-> [$depth]); |
127
|
|
|
|
|
|
|
|
128
|
|
|
|
|
|
|
# print +(' ' x $depth), "$depth: $r1 $r2\n"; |
129
|
|
|
|
|
|
|
|
130
|
795
|
100
|
100
|
|
|
6494
|
if ( |
|
|
100
|
100
|
|
|
|
|
131
|
|
|
|
|
|
|
( $w1->[$depth] and $w2->[$depth]) |
132
|
|
|
|
|
|
|
or $depth >= $#$d1 |
133
|
|
|
|
|
|
|
) { |
134
|
200
|
|
|
|
|
1275
|
$center = { |
135
|
|
|
|
|
|
|
range => [ $r1 , $r2 ], |
136
|
|
|
|
|
|
|
}; |
137
|
|
|
|
|
|
|
# print +(' ' x $depth), "T\n"; |
138
|
|
|
|
|
|
|
} elsif ( $r1 < $r2) { |
139
|
569
|
|
|
|
|
788
|
my ( @d1, @d2); |
140
|
|
|
|
|
|
|
# if, say, in '123' vs '145', '2' < '4' where depth = 1, |
141
|
|
|
|
|
|
|
# then d1 = 129 and d2 = 140 |
142
|
569
|
|
|
|
|
2000
|
for ( $i = 0; $i <= $depth; $i++) { |
143
|
1144
|
|
|
|
|
1877
|
$d1[$i] = $d1->[$i]; |
144
|
1144
|
|
|
|
|
2946
|
$d2[$i] = $d2->[$i]; |
145
|
|
|
|
|
|
|
} |
146
|
569
|
|
|
|
|
1585
|
for ( $i = $depth + 1; $i < @$d1; $i++) { |
147
|
1132
|
|
|
|
|
1908
|
$d1[$i] = $template-> [$i]->[2]; |
148
|
1132
|
|
|
|
|
2989
|
$d2[$i] = $template-> [$i]->[1]; |
149
|
|
|
|
|
|
|
} |
150
|
569
|
100
|
|
|
|
1402
|
if ( $w1->[$depth]) { |
151
|
287
|
|
|
|
|
362
|
$r1--; |
152
|
|
|
|
|
|
|
# print +(' ' x $depth), "LT\n"; |
153
|
|
|
|
|
|
|
} else { |
154
|
|
|
|
|
|
|
# print +(' ' x $depth), "$depth L > @$d1 : @d1 [@$w1]\n"; |
155
|
282
|
|
|
|
|
1947
|
$left = { |
156
|
|
|
|
|
|
|
next => range2tree( $template, $d1, \@d1, $w1, [(1) x @d1], $depth + 1), |
157
|
|
|
|
|
|
|
value => $r1, |
158
|
|
|
|
|
|
|
}; |
159
|
|
|
|
|
|
|
# print +(' ' x $depth), "$depth L <\n"; |
160
|
|
|
|
|
|
|
} |
161
|
|
|
|
|
|
|
|
162
|
569
|
100
|
|
|
|
1333
|
if ( $w2->[$depth]) { |
163
|
|
|
|
|
|
|
# print +(' ' x $depth), "RT\n"; |
164
|
282
|
|
|
|
|
455
|
$r2++; |
165
|
|
|
|
|
|
|
} else { |
166
|
|
|
|
|
|
|
# print +(' ' x $depth), "$depth R > @d2 : @$d2 [@$w2]\n"; |
167
|
287
|
|
|
|
|
1609
|
$right = { |
168
|
|
|
|
|
|
|
next => range2tree( $template, \@d2, $d2, [(1) x @d2], $w2, $depth + 1), |
169
|
|
|
|
|
|
|
value => $r2, |
170
|
|
|
|
|
|
|
}; |
171
|
|
|
|
|
|
|
# print +(' ' x $depth), "$depth R <\n"; |
172
|
|
|
|
|
|
|
} |
173
|
569
|
50
|
|
|
|
1560
|
if ( $r1 + 1 < $r2) { |
174
|
569
|
|
|
|
|
2463
|
$center = { |
175
|
|
|
|
|
|
|
range => [ $r1 + 1 , $r2 - 1 ], |
176
|
|
|
|
|
|
|
}; |
177
|
|
|
|
|
|
|
# print +(' ' x $depth), "$depth CT [ ", $r1+1, ' .. ', $r2-1, " ]\n"; |
178
|
|
|
|
|
|
|
} |
179
|
|
|
|
|
|
|
} else { |
180
|
26
|
|
|
|
|
119
|
$center = { |
181
|
|
|
|
|
|
|
next => range2tree( $template, $d1, $d2, $w1, $w2, $depth + 1), |
182
|
|
|
|
|
|
|
value => $r1, |
183
|
|
|
|
|
|
|
} |
184
|
|
|
|
|
|
|
} |
185
|
|
|
|
|
|
|
|
186
|
|
|
|
|
|
|
return [ |
187
|
795
|
100
|
|
|
|
5226
|
$left ? $left : (), |
|
|
50
|
|
|
|
|
|
|
|
100
|
|
|
|
|
|
188
|
|
|
|
|
|
|
$center ? $center : (), |
189
|
|
|
|
|
|
|
$right ? $right : () |
190
|
|
|
|
|
|
|
]; |
191
|
|
|
|
|
|
|
} |
192
|
|
|
|
|
|
|
|
193
|
|
|
|
|
|
|
# converts a tree into a regexp |
194
|
|
|
|
|
|
|
sub tree2re |
195
|
|
|
|
|
|
|
{ |
196
|
795
|
|
|
795
|
0
|
1220
|
my ( $template, $tree, $depth) = @_; |
197
|
795
|
|
|
|
|
853
|
my @q; |
198
|
795
|
|
|
|
|
1206
|
my $t = $template-> [$depth]; |
199
|
795
|
|
|
|
|
1582
|
for my $hash ( @$tree) { |
200
|
1364
|
100
|
|
|
|
2947
|
if ( exists $hash-> {value}) { |
201
|
595
|
100
|
|
|
|
2267
|
my $v = $t->[3] ? |
202
|
|
|
|
|
|
|
$t->[3]->[$hash->{value}] : |
203
|
|
|
|
|
|
|
match_range( $hash->{value}, $hash->{value}, $t->[4]); |
204
|
595
|
|
|
|
|
2499
|
push @q, $v . |
205
|
|
|
|
|
|
|
$t->[0] . |
206
|
|
|
|
|
|
|
tree2re( $template, $hash-> {next}, $depth + 1); |
207
|
|
|
|
|
|
|
} else { |
208
|
1059
|
|
|
|
|
2478
|
my $r = $t->[3] ? |
209
|
586
|
|
|
|
|
1655
|
re_group( map { $t->[3]->[$_] } |
210
|
|
|
|
|
|
|
$hash-> {range}-> [0] .. $hash-> {range}-> [1] ) : |
211
|
769
|
100
|
|
|
|
2677
|
match_range( @{$hash-> {range}}, $t->[4]); |
212
|
769
|
|
|
|
|
2946
|
push @q, $r . $t->[0]; |
213
|
|
|
|
|
|
|
} |
214
|
|
|
|
|
|
|
} |
215
|
|
|
|
|
|
|
|
216
|
795
|
|
|
|
|
1954
|
return re_group(@q); |
217
|
|
|
|
|
|
|
} |
218
|
|
|
|
|
|
|
|
219
|
|
|
|
|
|
|
1; |
220
|
|
|
|
|
|
|
|
221
|
|
|
|
|
|
|
__END__ |