| Filename | /usr/share/perl5/String/Random.pm |
| Statements | Executed 29 statements in 2.60ms |
| Calls | P | F | Exclusive Time |
Inclusive Time |
Subroutine |
|---|---|---|---|---|---|
| 1 | 1 | 1 | 17µs | 21µs | String::Random::BEGIN@17 |
| 1 | 1 | 1 | 13µs | 39µs | String::Random::BEGIN@18 |
| 1 | 1 | 1 | 12µs | 61µs | String::Random::BEGIN@20 |
| 1 | 1 | 1 | 5µs | 5µs | String::Random::BEGIN@21 |
| 0 | 0 | 0 | 0s | 0s | String::Random::__ANON__[:101] |
| 0 | 0 | 0 | 0s | 0s | String::Random::__ANON__[:119] |
| 0 | 0 | 0 | 0s | 0s | String::Random::__ANON__[:123] |
| 0 | 0 | 0 | 0s | 0s | String::Random::__ANON__[:127] |
| 0 | 0 | 0 | 0s | 0s | String::Random::__ANON__[:131] |
| 0 | 0 | 0 | 0s | 0s | String::Random::__ANON__[:173] |
| 0 | 0 | 0 | 0s | 0s | String::Random::__ANON__[:97] |
| 0 | 0 | 0 | 0s | 0s | String::Random::from_pattern |
| 0 | 0 | 0 | 0s | 0s | String::Random::new |
| 0 | 0 | 0 | 0s | 0s | String::Random::random_regex |
| 0 | 0 | 0 | 0s | 0s | String::Random::random_string |
| 0 | 0 | 0 | 0s | 0s | String::Random::randpattern |
| 0 | 0 | 0 | 0s | 0s | String::Random::randregex |
| 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 | 28µs | require 5.006_001; | ||
| 16 | |||||
| 17 | 3 | 28µs | 2 | 25µs | # spent 21µs (17+4) within String::Random::BEGIN@17 which was called:
# once (17µs+4µs) by C4::Members::BEGIN@28 at line 17 # spent 21µs making 1 call to String::Random::BEGIN@17
# spent 4µs making 1 call to strict::import |
| 18 | 3 | 31µs | 2 | 66µs | # spent 39µs (13+27) within String::Random::BEGIN@18 which was called:
# once (13µs+27µs) by C4::Members::BEGIN@28 at line 18 # spent 39µs making 1 call to String::Random::BEGIN@18
# spent 27µs making 1 call to warnings::import |
| 19 | |||||
| 20 | 3 | 29µs | 2 | 110µs | # spent 61µs (12+49) within String::Random::BEGIN@20 which was called:
# once (12µs+49µs) by C4::Members::BEGIN@28 at line 20 # spent 61µs making 1 call to String::Random::BEGIN@20
# spent 49µs making 1 call to Exporter::import |
| 21 | 3 | 2.01ms | 1 | 5µs | # spent 5µs within String::Random::BEGIN@21 which was called:
# once (5µs+0s) by C4::Members::BEGIN@28 at line 21 # spent 5µs making 1 call to String::Random::BEGIN@21 |
| 22 | |||||
| 23 | 1 | 13µs | our @ISA = qw(Exporter); | ||
| 24 | 1 | 3µs | our %EXPORT_TAGS = ( 'all' => [ qw( | ||
| 25 | &random_string | ||||
| 26 | &random_regex | ||||
| 27 | ) ] ); | ||||
| 28 | 1 | 3µs | our @EXPORT_OK = ( @{ $EXPORT_TAGS{'all'} } ); | ||
| 29 | 1 | 500ns | our @EXPORT = (); | ||
| 30 | 1 | 700ns | our $VERSION = '0.22'; | ||
| 31 | |||||
| 32 | # These are the various character sets. | ||||
| 33 | 1 | 11µs | our @upper=("A".."Z"); | ||
| 34 | 1 | 10µs | our @lower=("a".."z"); | ||
| 35 | 1 | 3µs | our @digit=("0".."9"); | ||
| 36 | 1 | 21µs | our @punct=map { chr($_); } (33..47,58..64,91..96,123..126); | ||
| 37 | 1 | 10µs | our @any=(@upper, @lower, @digit, @punct); | ||
| 38 | 1 | 11µs | our @salt=(@upper, @lower, @digit, ".", "/"); | ||
| 39 | 1 | 137µ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 | 58µ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 | 69µ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 | } else { | ||||
| 91 | carp "'\\$tmp' being treated as literal '$tmp'"; | ||||
| 92 | push(@{$string}, [$tmp]); | ||||
| 93 | } | ||||
| 94 | } else { | ||||
| 95 | croak "regex not terminated"; | ||||
| 96 | } | ||||
| 97 | }, | ||||
| 98 | '.' => sub { | ||||
| 99 | my ($self, $ch, $chars, $string)=@_; | ||||
| 100 | push(@{$string}, $patterns{$ch}); | ||||
| 101 | }, | ||||
| 102 | '[' => sub { | ||||
| 103 | my ($self, $ch, $chars, $string)=@_; | ||||
| 104 | my @tmp; | ||||
| 105 | while (defined($ch=shift(@{$chars})) && ($ch ne "]")) { | ||||
| 106 | if (($ch eq "-") && @{$chars} && @tmp) { | ||||
| 107 | $ch=shift(@{$chars}); | ||||
| 108 | for (my $n=ord($tmp[$#tmp]);$n<ord($ch);$n++) { | ||||
| 109 | push(@tmp, chr($n+1)); | ||||
| 110 | } | ||||
| 111 | } else { | ||||
| 112 | carp "'$ch' will be treated literally inside []" | ||||
| 113 | if ($ch=~/\W/); | ||||
| 114 | push(@tmp, $ch); | ||||
| 115 | } | ||||
| 116 | } | ||||
| 117 | croak "unmatched []" if ($ch ne "]"); | ||||
| 118 | push(@{$string}, \@tmp); | ||||
| 119 | }, | ||||
| 120 | '*' => sub { | ||||
| 121 | my ($self, $ch, $chars, $string)=@_; | ||||
| 122 | unshift(@{$chars}, split("", "{0,}")); | ||||
| 123 | }, | ||||
| 124 | '+' => sub { | ||||
| 125 | my ($self, $ch, $chars, $string)=@_; | ||||
| 126 | unshift(@{$chars}, split("", "{1,}")); | ||||
| 127 | }, | ||||
| 128 | '?' => sub { | ||||
| 129 | my ($self, $ch, $chars, $string)=@_; | ||||
| 130 | unshift(@{$chars}, split("", "{0,1}")); | ||||
| 131 | }, | ||||
| 132 | '{' => sub { | ||||
| 133 | my ($self, $ch, $chars, $string)=@_; | ||||
| 134 | my ($n, $closed); | ||||
| 135 | for ($n=0;$n<scalar(@{$chars});$n++) { | ||||
| 136 | if ($chars->[$n] eq "}") { | ||||
| 137 | $closed++; | ||||
| 138 | last; | ||||
| 139 | } | ||||
| 140 | } | ||||
| 141 | if ($closed) { | ||||
| 142 | my $tmp; | ||||
| 143 | while (defined($ch=shift(@{$chars})) && ($ch ne "}")) { | ||||
| 144 | croak "'$ch' inside {} not supported" if ($ch!~/[\d,]/); | ||||
| 145 | $tmp.=$ch; | ||||
| 146 | } | ||||
| 147 | if ($tmp=~/,/) { | ||||
| 148 | if (my ($min,$max) = $tmp =~ /^(\d*),(\d*)$/) { | ||||
| 149 | $min = 0 if (!length($min)); | ||||
| 150 | $max = $self->{'_max'} if (!length($max)); | ||||
| 151 | croak "bad range {$tmp}" if ($min>$max); | ||||
| 152 | if ($min == $max) { | ||||
| 153 | $tmp = $min; | ||||
| 154 | } else { | ||||
| 155 | $tmp = $min + int(rand($max - $min +1)); | ||||
| 156 | } | ||||
| 157 | } else { | ||||
| 158 | croak "malformed range {$tmp}"; | ||||
| 159 | } | ||||
| 160 | } | ||||
| 161 | if ($tmp) { | ||||
| 162 | my $last=$string->[$#{$string}]; | ||||
| 163 | for ($n=0;$n<($tmp-1);$n++) { | ||||
| 164 | push(@{$string}, $last); | ||||
| 165 | } | ||||
| 166 | } else { | ||||
| 167 | pop(@{$string}); | ||||
| 168 | } | ||||
| 169 | } else { | ||||
| 170 | # { isn't closed, so treat it literally. | ||||
| 171 | push(@{$string}, [$ch]); | ||||
| 172 | } | ||||
| 173 | }, | ||||
| 174 | 1 | 47µs | ); | ||
| 175 | |||||
| 176 | sub new { | ||||
| 177 | my $proto=shift; | ||||
| 178 | my $class=ref($proto) || $proto; | ||||
| 179 | my $self; | ||||
| 180 | $self={ %old_patterns }; # makes $self refer to a copy of %old_patterns | ||||
| 181 | my %args=(); | ||||
| 182 | %args=@_ if (@_); | ||||
| 183 | if (defined($args{'max'})) { | ||||
| 184 | $self->{'_max'}=$args{'max'}; | ||||
| 185 | } else { | ||||
| 186 | $self->{'_max'}=10; | ||||
| 187 | } | ||||
| 188 | return bless($self, $class); | ||||
| 189 | } | ||||
| 190 | |||||
| 191 | # Returns a random string for each regular expression given as an | ||||
| 192 | # argument, or the strings concatenated when used in a scalar context. | ||||
| 193 | sub randregex { | ||||
| 194 | my $self=shift; | ||||
| 195 | croak "called without a reference" if (!ref($self)); | ||||
| 196 | |||||
| 197 | my @strings=(); | ||||
| 198 | |||||
| 199 | while (defined(my $pattern=shift)) { | ||||
| 200 | my $ch; | ||||
| 201 | my @string=(); | ||||
| 202 | my $string=''; | ||||
| 203 | |||||
| 204 | # Split the characters in the pattern | ||||
| 205 | # up into a list for easier parsing. | ||||
| 206 | my @chars=split(//, $pattern); | ||||
| 207 | |||||
| 208 | while (defined($ch=shift(@chars))) { | ||||
| 209 | if (defined($regch{$ch})) { | ||||
| 210 | $regch{$ch}->($self, $ch, \@chars, \@string); | ||||
| 211 | } elsif ($ch=~/[\$\^\*\(\)\+\{\}\]\|\?]/) { | ||||
| 212 | # At least some of these probably should have special meaning. | ||||
| 213 | carp "'$ch' not implemented. treating literally."; | ||||
| 214 | push(@string, [$ch]); | ||||
| 215 | } else { | ||||
| 216 | push(@string, [$ch]); | ||||
| 217 | } | ||||
| 218 | } | ||||
| 219 | |||||
| 220 | foreach $ch (@string) { | ||||
| 221 | $string.=$ch->[int(rand(scalar(@{$ch})))]; | ||||
| 222 | } | ||||
| 223 | |||||
| 224 | push(@strings, $string); | ||||
| 225 | } | ||||
| 226 | |||||
| 227 | return wantarray ? @strings : join("", @strings); | ||||
| 228 | } | ||||
| 229 | |||||
| 230 | # For compatibility with an ancient version, please ignore... | ||||
| 231 | sub from_pattern { | ||||
| 232 | my $self=shift; | ||||
| 233 | croak "called without a reference" if (!ref($self)); | ||||
| 234 | |||||
| 235 | return $self->randpattern(@_); | ||||
| 236 | } | ||||
| 237 | |||||
| 238 | sub randpattern { | ||||
| 239 | my $self=shift; | ||||
| 240 | croak "called without a reference" if (!ref($self)); | ||||
| 241 | |||||
| 242 | my @strings=(); | ||||
| 243 | |||||
| 244 | while (defined(my $pattern=shift)) { | ||||
| 245 | my $string=''; | ||||
| 246 | |||||
| 247 | for my $ch (split(//, $pattern)) { | ||||
| 248 | if (defined($self->{$ch})) { | ||||
| 249 | $string.=$self->{$ch}->[int(rand(scalar(@{$self->{$ch}})))]; | ||||
| 250 | } else { | ||||
| 251 | croak qq(Unknown pattern character "$ch"!); | ||||
| 252 | } | ||||
| 253 | } | ||||
| 254 | push(@strings, $string); | ||||
| 255 | } | ||||
| 256 | |||||
| 257 | return wantarray ? @strings : join("", @strings); | ||||
| 258 | } | ||||
| 259 | |||||
| 260 | sub random_regex { | ||||
| 261 | my $foo=new String::Random; | ||||
| 262 | return $foo->randregex(@_); | ||||
| 263 | } | ||||
| 264 | |||||
| 265 | sub random_string { | ||||
| 266 | my($pattern,@list)=@_; | ||||
| 267 | |||||
| 268 | my($n,$foo); | ||||
| 269 | |||||
| 270 | $foo=new String::Random; | ||||
| 271 | |||||
| 272 | for ($n=0;$n<=$#list;$n++) { | ||||
| 273 | @{$foo->{$n}}=@{$list[$n]}; | ||||
| 274 | } | ||||
| 275 | |||||
| 276 | return $foo->randpattern($pattern); | ||||
| 277 | } | ||||
| 278 | |||||
| 279 | 1 | 80µs | 1; | ||
| 280 | __END__ |