=head1 NAME
-perlfaq4 - Data Manipulation ($Revision: 1.14 $, $Date: 2002/02/08 22:30:23 $)
+perlfaq4 - Data Manipulation ($Revision: 1.19 $, $Date: 2002/03/11 22:15:19 $)
=head1 DESCRIPTION
pseudorandom generator than comes with your operating system, look at
``Numerical Recipes in C'' at http://www.nr.com/ .
+=head2 How do I get a random number between X and Y?
+
+Use the following simple function. It selects a random integer between
+(and possibly including!) the two given integers, e.g.,
+C<random_int_in(50,120)>
+
+ sub random_int_in ($$) {
+ my($min, $max) = @_;
+ # Assumes that the two arguments are integers themselves!
+ return $min if $min == $max;
+ ($min, $max) = ($max, $min) if $min > $max;
+ return $min + int rand(1 + $max - $min);
+ }
+
=head1 Data: Dates
=head2 How do I find the week-of-the-year/day-of-the-year?
while ($string =~ /-\d+/g) { $count++ }
print "There are $count negative numbers in the string";
+Another version uses a global match in list context, then assigns the
+result to a scalar, producing a count of the number of matches.
+
+ $count = () = $string =~ /-\d+/g;
+
=head2 How do I capitalize all the words on one line?
To make the first letter of each word upper case:
That being said, there are several ways to approach this. If you
are going to make this query many times over arbitrary string values,
-the fastest way is probably to invert the original array and keep an
-associative array lying about whose keys are the first array's values.
+the fastest way is probably to invert the original array and maintain a
+hash whose keys are the first array's values.
@blues = qw/azure cerulean teal turquoise lapis-lazuli/;
- undef %is_blue;
+ %is_blue = ();
for (@blues) { $is_blue{$_} = 1 }
Now you can check whether $is_blue{$some_color}. It might have been a
array. This kind of an array will take up less space:
@primes = (2, 3, 5, 7, 11, 13, 17, 19, 23, 29, 31);
- undef @is_tiny_prime;
+ @is_tiny_prime = ();
for (@primes) { $is_tiny_prime[$_] = 1 }
# or simply @istiny_prime[@primes] = (1) x @primes;
if (/^-?\d+$/) { print "is an integer\n" }
if (/^[+-]?\d+$/) { print "is a +/- integer\n" }
if (/^-?\d+\.?\d*$/) { print "is a real number\n" }
- if (/^-?(?:\d+(?:\.\d*)?|\.\d+)$/) { print "is a decimal number" }
+ if (/^-?(?:\d+(?:\.\d*)?|\.\d+)$/) { print "is a decimal number\n" }
if (/^([+-]?)(?=\d|\.\d)\d*(\.\d*)?([Ee]([+-]?\d+))?$/)
- { print "a C float" }
+ { print "a C float\n" }
If you're on a POSIX system, Perl's supports the C<POSIX::strtod>
function. Its semantics are somewhat cumbersome, so here's a C<getnum>
=head1 NAME
-perlfaq5 - Files and Formats ($Revision: 1.9 $, $Date: 2002/02/11 19:30:21 $)
+perlfaq5 - Files and Formats ($Revision: 1.12 $, $Date: 2002/03/11 22:25:25 $)
=head1 DESCRIPTION
=head2 How can I output my numbers with commas added?
-This one will do it for you:
+This one from Benjamin Goldberg will do it for you:
- sub commify {
- my $number = shift;
- 1 while ($number =~ s/^([-+]?\d+)(\d{3})/$1,$2/);
- return $number;
- }
-
- $n = 23659019423.2331;
- print "GOT: ", commify($n), "\n";
-
- GOT: 23,659,019,423.2331
-
-You can't just:
-
- s/^([-+]?\d+)(\d{3})/$1,$2/g;
+ s/(^[-+]?\d+?(?=(?>(?:\d{3})+)(?!\d))|\G\d{3}(?=\d))/$1,/g;
-because you have to put the comma in and then recalculate your
-position.
+or written verbosely:
-Alternatively, this code commifies all numbers in a line regardless of
-whether they have decimal portions, are preceded by + or -, or
-whatever:
-
- # from Andrew Johnson <ajohnson@gpu.srv.ualberta.ca>
- sub commify {
- my $input = shift;
- $input = reverse $input;
- $input =~ s<(\d\d\d)(?=\d)(?!\d*\.)><$1,>g;
- return scalar reverse $input;
- }
+ s/(
+ ^[-+]? # beginning of number.
+ \d{1,3}? # first digits before first comma
+ (?= # followed by, (but not included in the match) :
+ (?>(?:\d{3})+) # some positive multiple of three digits.
+ (?!\d) # an *exact* multiple, not x * 3 + 1 or whatever.
+ )
+ | # or:
+ \G\d{3} # after the last group, get three digits
+ (?=\d) # but they have to have more digits after them.
+ )/$1,/xg;
=head2 How can I translate tildes (~) in a filename?
Normally perl ignores trailing blanks in filenames, and interprets
certain leading characters (or a trailing "|") to mean something
-special. To avoid this, you might want to use a routine like the one below.
-It turns incomplete pathnames into explicit relative ones, and tacks a
-trailing null byte on the name to make perl leave it alone:
-
- sub safe_filename {
- local $_ = shift;
- s#^([^./])#./$1#;
- $_ .= "\0";
- return $_;
- }
+special.
- $badpath = "<<<something really wicked ";
- $fn = safe_filename($badpath");
- open(FH, "> $fn") or "couldn't open $badpath: $!";
+The three argument form of open() lets you specify the mode
+separately from the filename. The open() function treats
+special mode characters and whitespace in the filename as
+literals
-This assumes that you are using POSIX (portable operating systems
-interface) paths. If you are on a closed, non-portable, proprietary
-system, you may have to adjust the C<"./"> above.
+ open FILE, "<", " file "; # filename is " file "
+ open FILE, ">", ">file"; # filename is ">file"
+
-It would be a lot clearer to use sysopen(), though:
+It may be a lot clearer to use sysopen(), though:
use Fcntl;
$badpath = "<<<something really wicked ";
sysopen (FH, $badpath, O_WRONLY | O_CREAT | O_TRUNC)
or die "can't open $badpath: $!";
-For more information, see also the new L<perlopentut> if you have it
-(new for 5.6).
-
=head2 How can I reliably rename a file?
If your operating system supports a proper mv(1) utility or its functional
=head2 How do I get a file's timestamp in perl?
-If you want to retrieve the time at which the file was last read,
-written, or had its meta-data (owner, etc) changed, you use the B<-M>,
-B<-A>, or B<-C> file test operations as documented in L<perlfunc>. These
-retrieve the age of the file (measured against the start-time of your
-program) in days as a floating point number. To retrieve the "raw"
-time in seconds since the epoch, you would call the stat function,
-then use localtime(), gmtime(), or POSIX::strftime() to convert this
-into human-readable form.
+If you want to retrieve the time at which the file was last
+read, written, or had its meta-data (owner, etc) changed,
+you use the B<-M>, B<-A>, or B<-C> file test operations as
+documented in L<perlfunc>. These retrieve the age of the
+file (measured against the start-time of your program) in
+days as a floating point number. Some platforms may not have
+all of these times. See L<perlport> for details. To
+retrieve the "raw" time in seconds since the epoch, you
+would call the stat function, then use localtime(),
+gmtime(), or POSIX::strftime() to convert this into
+human-readable form.
Here's an example: