| 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__ |