Filename | /usr/share/perl5/String/Random.pm |
Statements | Executed 25 statements in 1.72ms |
Calls | P | F | Exclusive Time |
Inclusive Time |
Subroutine |
---|---|---|---|---|---|
1 | 1 | 1 | 12µs | 24µs | BEGIN@17 | String::Random::
1 | 1 | 1 | 8µs | 15µs | BEGIN@18 | String::Random::
1 | 1 | 1 | 7µs | 34µs | BEGIN@20 | String::Random::
1 | 1 | 1 | 3µs | 3µs | BEGIN@21 | String::Random::
0 | 0 | 0 | 0s | 0s | __ANON__[:100] | String::Random::
0 | 0 | 0 | 0s | 0s | __ANON__[:104] | String::Random::
0 | 0 | 0 | 0s | 0s | __ANON__[:122] | String::Random::
0 | 0 | 0 | 0s | 0s | __ANON__[:126] | String::Random::
0 | 0 | 0 | 0s | 0s | __ANON__[:130] | String::Random::
0 | 0 | 0 | 0s | 0s | __ANON__[:134] | String::Random::
0 | 0 | 0 | 0s | 0s | __ANON__[:176] | String::Random::
0 | 0 | 0 | 0s | 0s | from_pattern | String::Random::
0 | 0 | 0 | 0s | 0s | new | String::Random::
0 | 0 | 0 | 0s | 0s | random_regex | String::Random::
0 | 0 | 0 | 0s | 0s | random_string | String::Random::
0 | 0 | 0 | 0s | 0s | randpattern | String::Random::
0 | 0 | 0 | 0s | 0s | randregex | String::Random::
Line | State ments |
Time on line |
Calls | Time in subs |
Code |
---|---|---|---|---|---|
1 | # String::Random - Generates a random string from a pattern | ||||
2 | # Copyright (C) 1999-2006 Steven Pritchard <steve@silug.org> | ||||
3 | # | ||||
4 | # This program is free software; you can redistribute it | ||||
5 | # and/or modify it under the same terms as Perl itself. | ||||
6 | # | ||||
7 | # This program is distributed in the hope that it will be useful, | ||||
8 | # but WITHOUT ANY WARRANTY; without even the implied warranty of | ||||
9 | # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. | ||||
10 | # | ||||
11 | # $Id: Random.pm,v 1.4 2006/09/21 17:34:07 steve Exp $ | ||||
12 | |||||
13 | package String::Random; | ||||
14 | |||||
15 | 1 | 11µs | require 5.006_001; | ||
16 | |||||
17 | 2 | 23µs | 2 | 36µs | # spent 24µs (12+12) within String::Random::BEGIN@17 which was called:
# once (12µs+12µs) by C4::Members::BEGIN@27 at line 17 # spent 24µs making 1 call to String::Random::BEGIN@17
# spent 12µs making 1 call to strict::import |
18 | 2 | 20µs | 2 | 23µs | # spent 15µs (8+8) within String::Random::BEGIN@18 which was called:
# once (8µs+8µs) by C4::Members::BEGIN@27 at line 18 # spent 15µs making 1 call to String::Random::BEGIN@18
# spent 8µs making 1 call to warnings::import |
19 | |||||
20 | 2 | 21µs | 2 | 62µs | # spent 34µs (7+28) within String::Random::BEGIN@20 which was called:
# once (7µs+28µs) by C4::Members::BEGIN@27 at line 20 # spent 34µs making 1 call to String::Random::BEGIN@20
# spent 28µs making 1 call to Exporter::import |
21 | 2 | 1.42ms | 1 | 3µs | # spent 3µs within String::Random::BEGIN@21 which was called:
# once (3µs+0s) by C4::Members::BEGIN@27 at line 21 # spent 3µs making 1 call to String::Random::BEGIN@21 |
22 | |||||
23 | 1 | 6µs | our @ISA = qw(Exporter); | ||
24 | 1 | 1µs | our %EXPORT_TAGS = ( 'all' => [ qw( | ||
25 | &random_string | ||||
26 | &random_regex | ||||
27 | ) ] ); | ||||
28 | 1 | 800ns | our @EXPORT_OK = ( @{ $EXPORT_TAGS{'all'} } ); | ||
29 | 1 | 200ns | our @EXPORT = (); | ||
30 | 1 | 200ns | our $VERSION = '0.26'; | ||
31 | |||||
32 | # These are the various character sets. | ||||
33 | 1 | 2µs | our @upper=("A".."Z"); | ||
34 | 1 | 2µs | our @lower=("a".."z"); | ||
35 | 1 | 900ns | our @digit=("0".."9"); | ||
36 | 1 | 11µs | our @punct=map { chr($_); } (33..47,58..64,91..96,123..126); | ||
37 | 1 | 7µs | our @any=(@upper, @lower, @digit, @punct); | ||
38 | 1 | 6µs | our @salt=(@upper, @lower, @digit, ".", "/"); | ||
39 | 1 | 69µs | our @binary=map { chr($_) } (0..255); | ||
40 | |||||
41 | # What's important is how they relate to the pattern characters. | ||||
42 | # These are the old patterns for randpattern/random_string. | ||||
43 | 1 | 47µs | our %old_patterns = ( | ||
44 | 'C' => [ @upper ], | ||||
45 | 'c' => [ @lower ], | ||||
46 | 'n' => [ @digit ], | ||||
47 | '!' => [ @punct ], | ||||
48 | '.' => [ @any ], | ||||
49 | 's' => [ @salt ], | ||||
50 | 'b' => [ @binary ], | ||||
51 | ); | ||||
52 | |||||
53 | # These are the regex-based patterns. | ||||
54 | our %patterns = ( | ||||
55 | # These are the regex-equivalents. | ||||
56 | '.' => [ @any ], | ||||
57 | '\d' => [ @digit ], | ||||
58 | '\D' => [ @upper, @lower, @punct ], | ||||
59 | '\w' => [ @upper, @lower, @digit, "_" ], | ||||
60 | 1 | 44µs | '\W' => [ grep { $_ ne "_" } @punct ], | ||
61 | '\s' => [ " ", "\t" ], # Would anything else make sense? | ||||
62 | '\S' => [ @upper, @lower, @digit, @punct ], | ||||
63 | |||||
64 | # These are translated to their double quoted equivalents. | ||||
65 | '\t' => [ "\t" ], | ||||
66 | '\n' => [ "\n" ], | ||||
67 | '\r' => [ "\r" ], | ||||
68 | '\f' => [ "\f" ], | ||||
69 | '\a' => [ "\a" ], | ||||
70 | '\e' => [ "\e" ], | ||||
71 | ); | ||||
72 | |||||
73 | # These characters are treated specially in randregex(). | ||||
74 | our %regch = ( | ||||
75 | "\\" => sub { | ||||
76 | my ($self, $ch, $chars, $string)=@_; | ||||
77 | if (@{$chars}) { | ||||
78 | my $tmp=shift(@{$chars}); | ||||
79 | if ($tmp eq "x") { | ||||
80 | # This is supposed to be a number in hex, so | ||||
81 | # there had better be at least 2 characters left. | ||||
82 | $tmp=shift(@{$chars}) . shift(@{$chars}); | ||||
83 | push(@{$string}, [chr(hex($tmp))]); | ||||
84 | } elsif ($tmp=~/[0-7]/) { | ||||
85 | carp "octal parsing not implemented. treating literally."; | ||||
86 | push(@{$string}, [$tmp]); | ||||
87 | } elsif (defined($patterns{"\\$tmp"})) { | ||||
88 | $ch.=$tmp; | ||||
89 | push(@{$string}, $patterns{$ch}); | ||||
90 | } | ||||
91 | else { | ||||
92 | if ($tmp =~ /\w/) { | ||||
93 | carp "'\\$tmp' being treated as literal '$tmp'"; | ||||
94 | } | ||||
95 | push(@{$string}, [$tmp]); | ||||
96 | } | ||||
97 | } else { | ||||
98 | croak "regex not terminated"; | ||||
99 | } | ||||
100 | }, | ||||
101 | '.' => sub { | ||||
102 | my ($self, $ch, $chars, $string)=@_; | ||||
103 | push(@{$string}, $patterns{$ch}); | ||||
104 | }, | ||||
105 | '[' => sub { | ||||
106 | my ($self, $ch, $chars, $string)=@_; | ||||
107 | my @tmp; | ||||
108 | while (defined($ch=shift(@{$chars})) && ($ch ne "]")) { | ||||
109 | if (($ch eq "-") && @{$chars} && @tmp) { | ||||
110 | $ch=shift(@{$chars}); | ||||
111 | for (my $n=ord($tmp[$#tmp]);$n<ord($ch);$n++) { | ||||
112 | push(@tmp, chr($n+1)); | ||||
113 | } | ||||
114 | } else { | ||||
115 | carp "'$ch' will be treated literally inside []" | ||||
116 | if ($ch=~/\W/); | ||||
117 | push(@tmp, $ch); | ||||
118 | } | ||||
119 | } | ||||
120 | croak "unmatched []" if ($ch ne "]"); | ||||
121 | push(@{$string}, \@tmp); | ||||
122 | }, | ||||
123 | '*' => sub { | ||||
124 | my ($self, $ch, $chars, $string)=@_; | ||||
125 | unshift(@{$chars}, split("", "{0,}")); | ||||
126 | }, | ||||
127 | '+' => sub { | ||||
128 | my ($self, $ch, $chars, $string)=@_; | ||||
129 | unshift(@{$chars}, split("", "{1,}")); | ||||
130 | }, | ||||
131 | '?' => sub { | ||||
132 | my ($self, $ch, $chars, $string)=@_; | ||||
133 | unshift(@{$chars}, split("", "{0,1}")); | ||||
134 | }, | ||||
135 | '{' => sub { | ||||
136 | my ($self, $ch, $chars, $string)=@_; | ||||
137 | my ($n, $closed); | ||||
138 | for ($n=0;$n<scalar(@{$chars});$n++) { | ||||
139 | if ($chars->[$n] eq "}") { | ||||
140 | $closed++; | ||||
141 | last; | ||||
142 | } | ||||
143 | } | ||||
144 | if ($closed) { | ||||
145 | my $tmp; | ||||
146 | while (defined($ch=shift(@{$chars})) && ($ch ne "}")) { | ||||
147 | croak "'$ch' inside {} not supported" if ($ch!~/[\d,]/); | ||||
148 | $tmp.=$ch; | ||||
149 | } | ||||
150 | if ($tmp=~/,/) { | ||||
151 | if (my ($min,$max) = $tmp =~ /^(\d*),(\d*)$/) { | ||||
152 | $min = 0 if (!length($min)); | ||||
153 | $max = $self->{'_max'} if (!length($max)); | ||||
154 | croak "bad range {$tmp}" if ($min>$max); | ||||
155 | if ($min == $max) { | ||||
156 | $tmp = $min; | ||||
157 | } else { | ||||
158 | $tmp = $min + int(rand($max - $min +1)); | ||||
159 | } | ||||
160 | } else { | ||||
161 | croak "malformed range {$tmp}"; | ||||
162 | } | ||||
163 | } | ||||
164 | if ($tmp) { | ||||
165 | my $last=$string->[$#{$string}]; | ||||
166 | for ($n=0;$n<($tmp-1);$n++) { | ||||
167 | push(@{$string}, $last); | ||||
168 | } | ||||
169 | } else { | ||||
170 | pop(@{$string}); | ||||
171 | } | ||||
172 | } else { | ||||
173 | # { isn't closed, so treat it literally. | ||||
174 | push(@{$string}, [$ch]); | ||||
175 | } | ||||
176 | }, | ||||
177 | 1 | 13µs | ); | ||
178 | |||||
179 | sub new { | ||||
180 | my $proto=shift; | ||||
181 | my $class=ref($proto) || $proto; | ||||
182 | my $self; | ||||
183 | $self={ %old_patterns }; # makes $self refer to a copy of %old_patterns | ||||
184 | my %args=(); | ||||
185 | %args=@_ if (@_); | ||||
186 | if (defined($args{'max'})) { | ||||
187 | $self->{'_max'}=$args{'max'}; | ||||
188 | } else { | ||||
189 | $self->{'_max'}=10; | ||||
190 | } | ||||
191 | return bless($self, $class); | ||||
192 | } | ||||
193 | |||||
194 | # Returns a random string for each regular expression given as an | ||||
195 | # argument, or the strings concatenated when used in a scalar context. | ||||
196 | sub randregex { | ||||
197 | my $self=shift; | ||||
198 | croak "called without a reference" if (!ref($self)); | ||||
199 | |||||
200 | my @strings=(); | ||||
201 | |||||
202 | while (defined(my $pattern=shift)) { | ||||
203 | my $ch; | ||||
204 | my @string=(); | ||||
205 | my $string=''; | ||||
206 | |||||
207 | # Split the characters in the pattern | ||||
208 | # up into a list for easier parsing. | ||||
209 | my @chars=split(//, $pattern); | ||||
210 | |||||
211 | while (defined($ch=shift(@chars))) { | ||||
212 | if (defined($regch{$ch})) { | ||||
213 | $regch{$ch}->($self, $ch, \@chars, \@string); | ||||
214 | } elsif ($ch=~/[\$\^\*\(\)\+\{\}\]\|\?]/) { | ||||
215 | # At least some of these probably should have special meaning. | ||||
216 | carp "'$ch' not implemented. treating literally."; | ||||
217 | push(@string, [$ch]); | ||||
218 | } else { | ||||
219 | push(@string, [$ch]); | ||||
220 | } | ||||
221 | } | ||||
222 | |||||
223 | foreach $ch (@string) { | ||||
224 | $string.=$ch->[int(rand(scalar(@{$ch})))]; | ||||
225 | } | ||||
226 | |||||
227 | push(@strings, $string); | ||||
228 | } | ||||
229 | |||||
230 | return wantarray ? @strings : join("", @strings); | ||||
231 | } | ||||
232 | |||||
233 | # For compatibility with an ancient version, please ignore... | ||||
234 | sub from_pattern { | ||||
235 | my $self=shift; | ||||
236 | croak "called without a reference" if (!ref($self)); | ||||
237 | |||||
238 | return $self->randpattern(@_); | ||||
239 | } | ||||
240 | |||||
241 | sub randpattern { | ||||
242 | my $self=shift; | ||||
243 | croak "called without a reference" if (!ref($self)); | ||||
244 | |||||
245 | my @strings=(); | ||||
246 | |||||
247 | while (defined(my $pattern=shift)) { | ||||
248 | my $string=''; | ||||
249 | |||||
250 | for my $ch (split(//, $pattern)) { | ||||
251 | if (defined($self->{$ch})) { | ||||
252 | $string.=$self->{$ch}->[int(rand(scalar(@{$self->{$ch}})))]; | ||||
253 | } else { | ||||
254 | croak qq(Unknown pattern character "$ch"!); | ||||
255 | } | ||||
256 | } | ||||
257 | push(@strings, $string); | ||||
258 | } | ||||
259 | |||||
260 | return wantarray ? @strings : join("", @strings); | ||||
261 | } | ||||
262 | |||||
263 | sub random_regex { | ||||
264 | my $foo=new String::Random; | ||||
265 | return $foo->randregex(@_); | ||||
266 | } | ||||
267 | |||||
268 | sub random_string { | ||||
269 | my($pattern,@list)=@_; | ||||
270 | |||||
271 | my($n,$foo); | ||||
272 | |||||
273 | $foo=new String::Random; | ||||
274 | |||||
275 | for ($n=0;$n<=$#list;$n++) { | ||||
276 | @{$foo->{$n}}=@{$list[$n]}; | ||||
277 | } | ||||
278 | |||||
279 | return $foo->randpattern($pattern); | ||||
280 | } | ||||
281 | |||||
282 | 1 | 15µs | 1; | ||
283 | __END__ |