line |
stmt |
bran |
cond |
sub |
pod |
time |
code |
1
|
|
|
|
|
|
|
package Regexp::NumRange; |
2
|
|
|
|
|
|
|
|
3
|
4
|
|
|
4
|
|
112431
|
use 5.006; |
|
4
|
|
|
|
|
15
|
|
|
4
|
|
|
|
|
168
|
|
4
|
4
|
|
|
4
|
|
23
|
use strict; |
|
4
|
|
|
|
|
7
|
|
|
4
|
|
|
|
|
138
|
|
5
|
4
|
|
|
4
|
|
20
|
use warnings; |
|
4
|
|
|
|
|
13
|
|
|
4
|
|
|
|
|
108
|
|
6
|
4
|
|
|
4
|
|
21
|
use Carp; |
|
4
|
|
|
|
|
8
|
|
|
4
|
|
|
|
|
558
|
|
7
|
4
|
|
|
4
|
|
3646
|
use POSIX qw( ceil ); |
|
4
|
|
|
|
|
30133
|
|
|
4
|
|
|
|
|
29
|
|
8
|
|
|
|
|
|
|
|
9
|
4
|
|
|
4
|
|
4923
|
use base 'Exporter'; |
|
4
|
|
|
|
|
7
|
|
|
4
|
|
|
|
|
4300
|
|
10
|
|
|
|
|
|
|
our @EXPORT_OK = qw( rx_range rx_max ); |
11
|
|
|
|
|
|
|
|
12
|
|
|
|
|
|
|
=head1 NAME |
13
|
|
|
|
|
|
|
|
14
|
|
|
|
|
|
|
Regexp::NumRange - Create Regular Expressions for numeric ranges |
15
|
|
|
|
|
|
|
|
16
|
|
|
|
|
|
|
=head1 VERSION |
17
|
|
|
|
|
|
|
|
18
|
|
|
|
|
|
|
Version 0.03 |
19
|
|
|
|
|
|
|
|
20
|
|
|
|
|
|
|
=cut |
21
|
|
|
|
|
|
|
|
22
|
|
|
|
|
|
|
our $VERSION = '0.03'; |
23
|
|
|
|
|
|
|
|
24
|
|
|
|
|
|
|
=head1 SYNOPSIS |
25
|
|
|
|
|
|
|
|
26
|
|
|
|
|
|
|
B is a package for generating regular expression strings. These strings can be used in a regular expression to correctly match numeric strings within only a specified range. |
27
|
|
|
|
|
|
|
|
28
|
|
|
|
|
|
|
Example Usage: |
29
|
|
|
|
|
|
|
|
30
|
|
|
|
|
|
|
use Test::More; |
31
|
|
|
|
|
|
|
use Regexp::NumRange qw/ rx_max /; |
32
|
|
|
|
|
|
|
|
33
|
|
|
|
|
|
|
my $rx = rx_max(255); |
34
|
|
|
|
|
|
|
|
35
|
|
|
|
|
|
|
like '100', qr/^$rx$/, '100 is less than 255'; |
36
|
|
|
|
|
|
|
unlike '256', qr/^$rx$/, '256 is greater tha 255'; |
37
|
|
|
|
|
|
|
|
38
|
|
|
|
|
|
|
=head1 EXPORT |
39
|
|
|
|
|
|
|
|
40
|
|
|
|
|
|
|
Exports Available: |
41
|
|
|
|
|
|
|
|
42
|
|
|
|
|
|
|
use Regexp::NumRange qw/ rx_max rx_range /; |
43
|
|
|
|
|
|
|
|
44
|
|
|
|
|
|
|
=head1 SUBROUTINES/METHODS |
45
|
|
|
|
|
|
|
|
46
|
|
|
|
|
|
|
=head2 rx_range |
47
|
|
|
|
|
|
|
|
48
|
|
|
|
|
|
|
Create a regex string between two arbitrary integers. |
49
|
|
|
|
|
|
|
|
50
|
|
|
|
|
|
|
use Test::More; |
51
|
|
|
|
|
|
|
use Regexp::NumRange qw/ rx_range /; |
52
|
|
|
|
|
|
|
|
53
|
|
|
|
|
|
|
my $string = rx_range(256, 1024); |
54
|
|
|
|
|
|
|
my $rx = qr/^$string$/; |
55
|
|
|
|
|
|
|
|
56
|
|
|
|
|
|
|
ok "10" !~ $rx; |
57
|
|
|
|
|
|
|
ok "300" =~ $rx; |
58
|
|
|
|
|
|
|
ok "2000" !~ $rx; |
59
|
|
|
|
|
|
|
|
60
|
|
|
|
|
|
|
=cut |
61
|
|
|
|
|
|
|
|
62
|
|
|
|
|
|
|
sub rx_range { |
63
|
18
|
|
|
18
|
1
|
117941
|
my ( $s, $e ) = @_; |
64
|
18
|
|
|
|
|
38
|
$s = int($s); |
65
|
18
|
|
|
|
|
39
|
$e = int($e); |
66
|
18
|
100
|
|
|
|
83
|
( $s, $e ) = ( $e, $s ) if $e < $s; |
67
|
18
|
100
|
|
|
|
74
|
return rx_max($e) if $s == 0; |
68
|
|
|
|
|
|
|
|
69
|
16
|
|
|
|
|
90
|
my @ds = split //, "$s"; |
70
|
16
|
|
|
|
|
71
|
my @de = split //, "$e"; |
71
|
|
|
|
|
|
|
|
72
|
16
|
|
|
|
|
33
|
my $maxd = scalar @de; |
73
|
16
|
|
|
|
|
35
|
my $mind = scalar @ds; |
74
|
16
|
|
|
|
|
68
|
my $diff = $maxd - $mind; |
75
|
|
|
|
|
|
|
|
76
|
16
|
|
|
|
|
34
|
my $rx = '('; |
77
|
|
|
|
|
|
|
|
78
|
|
|
|
|
|
|
# after last significant digit |
79
|
16
|
|
|
|
|
47
|
my @l = @de; |
80
|
16
|
|
|
|
|
44
|
my $a = 0; |
81
|
16
|
100
|
100
|
|
|
104
|
if ( $diff || $de[0] - $ds[0] >= 1 ) { |
82
|
14
|
|
|
|
|
46
|
while ( scalar(@l) >= 2 ) { |
83
|
32
|
|
|
|
|
72
|
my $d = pop @l; |
84
|
32
|
100
|
|
|
|
87
|
my $ld = ( $a == 0 ) ? $d : $d - 1; |
85
|
32
|
100
|
|
|
|
141
|
next if $ld < 0; |
86
|
25
|
|
|
|
|
181
|
$rx .= join( '', @l ); |
87
|
25
|
|
|
|
|
57
|
$rx .= "[0-$ld]"; |
88
|
25
|
100
|
|
|
|
67
|
$rx .= "[0-9]" if $a >= 1; |
89
|
25
|
100
|
|
|
|
70
|
$rx .= "{$a}" if $a > 1; |
90
|
25
|
|
|
|
|
39
|
$rx .= '|'; |
91
|
25
|
|
|
|
|
145
|
$a++; |
92
|
|
|
|
|
|
|
} |
93
|
|
|
|
|
|
|
} |
94
|
|
|
|
|
|
|
|
95
|
|
|
|
|
|
|
# counting up to common digits |
96
|
16
|
100
|
|
|
|
53
|
if ($diff) { |
|
|
100
|
|
|
|
|
|
97
|
11
|
|
|
|
|
26
|
my $min = $ds[0] + 1; |
98
|
11
|
50
|
|
|
|
31
|
if ( $min <= 9 ) { |
99
|
11
|
|
|
|
|
15
|
my $n = $mind - 1; |
100
|
11
|
|
|
|
|
32
|
$rx .= "[$min-9]"; |
101
|
11
|
100
|
|
|
|
40
|
$rx .= "[0-9]{$n}" if $n >= 1; |
102
|
11
|
|
|
|
|
25
|
$rx .= '|'; |
103
|
|
|
|
|
|
|
} |
104
|
|
|
|
|
|
|
} |
105
|
|
|
|
|
|
|
elsif ( $de[0] - $ds[0] > 1 ) { |
106
|
|
|
|
|
|
|
|
107
|
|
|
|
|
|
|
# betwixt same digit |
108
|
2
|
|
|
|
|
7
|
my $n = $mind - 1; |
109
|
2
|
|
|
|
|
4
|
my $d1 = $ds[0] + 1; |
110
|
2
|
|
|
|
|
4
|
my $d2 = $de[0] - 1; |
111
|
2
|
|
|
|
|
7
|
$rx .= "[$d1-$d2]"; |
112
|
2
|
50
|
|
|
|
10
|
$rx .= "[0-9]{$n}" if $n >= 1; |
113
|
2
|
|
|
|
|
5
|
$rx .= '|'; |
114
|
|
|
|
|
|
|
} |
115
|
|
|
|
|
|
|
|
116
|
|
|
|
|
|
|
# lowest digit |
117
|
|
|
|
|
|
|
{ |
118
|
16
|
|
|
|
|
27
|
my $m = $mind - 2; |
|
16
|
|
|
|
|
31
|
|
119
|
16
|
|
|
|
|
160
|
my $l = $ds[-1]; |
120
|
16
|
100
|
66
|
|
|
95
|
my $md = ( $ds[0] == $de[0] && !$diff ) ? $de[-1] : 9; |
121
|
16
|
|
|
|
|
62
|
$rx .= join( '', @ds[ 0 .. $m ] ); |
122
|
16
|
|
|
|
|
45
|
$rx .= "[$l-$md]"; |
123
|
16
|
|
|
|
|
35
|
$rx .= '|'; |
124
|
|
|
|
|
|
|
} |
125
|
|
|
|
|
|
|
|
126
|
|
|
|
|
|
|
# full middle digit ranges |
127
|
16
|
|
|
|
|
25
|
my $om = -1; |
128
|
16
|
|
|
|
|
46
|
while ( $diff > 1 ) { |
129
|
6
|
|
|
|
|
11
|
my $m = $maxd - $diff + 1; |
130
|
6
|
100
|
|
|
|
24
|
my $r = ( $m == $maxd - 1 ) ? $de[0] - 1 : 9; |
131
|
6
|
|
|
|
|
7
|
$diff--; |
132
|
6
|
100
|
|
|
|
18
|
if ( $r <= 0 ) { |
133
|
1
|
|
|
|
|
2
|
$r = 9; |
134
|
1
|
|
|
|
|
2
|
$m--; |
135
|
|
|
|
|
|
|
} |
136
|
6
|
50
|
|
|
|
25
|
$rx .= "[1-$r]" if $r >= 1; |
137
|
6
|
|
|
|
|
8
|
$rx .= '[0-9]'; |
138
|
6
|
50
|
|
|
|
20
|
$rx .= "{$m}" if $r > 1; |
139
|
6
|
|
|
|
|
7
|
$rx .= '|'; |
140
|
6
|
|
|
|
|
18
|
$om = $m; |
141
|
|
|
|
|
|
|
} |
142
|
16
|
100
|
|
|
|
43
|
if ( $diff == 1 ) { |
143
|
11
|
|
|
|
|
19
|
my $m = $maxd - 1; |
144
|
11
|
|
|
|
|
21
|
my $r = $de[0] - 1; |
145
|
11
|
100
|
|
|
|
28
|
if ( $m == $om ) { |
146
|
3
|
|
|
|
|
5
|
$r = 9; |
147
|
3
|
|
|
|
|
6
|
$m = $mind; |
148
|
|
|
|
|
|
|
} |
149
|
11
|
100
|
|
|
|
27
|
if ( $r >= 1 ) { |
150
|
6
|
|
|
|
|
16
|
$rx .= "[1-$r]"; |
151
|
6
|
50
|
|
|
|
28
|
$rx .= "[0-9]" if $m >= 1; |
152
|
6
|
100
|
|
|
|
26
|
$rx .= "{$m}" if $m > 1; |
153
|
6
|
|
|
|
|
11
|
$rx .= '|'; |
154
|
|
|
|
|
|
|
} |
155
|
11
|
|
|
|
|
19
|
$m--; |
156
|
|
|
|
|
|
|
} |
157
|
|
|
|
|
|
|
|
158
|
16
|
|
|
|
|
113
|
$rx =~ s/\|$//; |
159
|
16
|
|
|
|
|
26
|
$rx .= ')'; |
160
|
16
|
|
|
|
|
93
|
return $rx; |
161
|
|
|
|
|
|
|
} |
162
|
|
|
|
|
|
|
|
163
|
|
|
|
|
|
|
=head2 rx_max |
164
|
|
|
|
|
|
|
|
165
|
|
|
|
|
|
|
Create a regex string between 0 and an arbitrary integer. |
166
|
|
|
|
|
|
|
|
167
|
|
|
|
|
|
|
my $rx_string = rx_max(1024); # create a string matching numbers between 0 and 1024 |
168
|
|
|
|
|
|
|
is $rx_string, '(102[0-4]|10[0-1][0-9]|0?[0-9]{1,3})'; |
169
|
|
|
|
|
|
|
|
170
|
|
|
|
|
|
|
=cut |
171
|
|
|
|
|
|
|
|
172
|
|
|
|
|
|
|
sub rx_max { |
173
|
68
|
|
|
68
|
1
|
2591
|
my ($max) = @_; |
174
|
68
|
|
|
|
|
94
|
$max = int($max); |
175
|
68
|
100
|
|
|
|
170
|
return "[0-$max]" if $max <= 9; |
176
|
63
|
|
|
|
|
88
|
my $rx = '('; |
177
|
63
|
|
|
|
|
248
|
my @digits = split //, "$max"; |
178
|
63
|
|
|
|
|
93
|
my $after = 0; |
179
|
63
|
|
|
|
|
154
|
while ( scalar(@digits) ) { |
180
|
178
|
|
|
|
|
236
|
$after++; |
181
|
178
|
|
|
|
|
253
|
my $d = pop @digits; |
182
|
178
|
100
|
|
|
|
407
|
my $ld = ( $after == 1 ) ? $d : $d - 1; |
183
|
178
|
100
|
|
|
|
329
|
my $first = scalar(@digits) ? 0 : 1; |
184
|
178
|
50
|
66
|
|
|
499
|
next if $ld < 0 && $after > 1 && !$first; |
|
|
|
66
|
|
|
|
|
185
|
165
|
|
|
|
|
293
|
$rx .= join( '', @digits ); |
186
|
165
|
100
|
|
|
|
340
|
$rx .= ( $ld < 1 ) ? '0' : "[0-$ld]"; |
187
|
165
|
100
|
|
|
|
287
|
$rx .= $first ? '?' : ''; |
188
|
165
|
100
|
|
|
|
369
|
$rx .= "[0-9]" if $after > 1; |
189
|
165
|
50
|
|
|
|
361
|
$rx .= $first ? '{1,' : '{' if $after > 2; |
|
|
100
|
|
|
|
|
|
190
|
165
|
100
|
|
|
|
323
|
$rx .= ( $after - 1 ) . '}' if $after > 2; |
191
|
165
|
100
|
|
|
|
670
|
$rx .= '|' unless $first; |
192
|
|
|
|
|
|
|
} |
193
|
63
|
|
|
|
|
292
|
return $rx . ')'; |
194
|
|
|
|
|
|
|
} |
195
|
|
|
|
|
|
|
|
196
|
|
|
|
|
|
|
1; |
197
|
|
|
|
|
|
|
|
198
|
|
|
|
|
|
|
__END__ |