Perl Circus - Three Rings of Perl Tricks.

Scalars

from perldoc perlintro... A scalar represents a single value:

my $animal = "camel";
my $answer = 42;

Scalar values can be strings, integers or floating point numbers, and Perl will automatically convert between them as required. There is no need to pre-declare your variable types.

Scalar values can be used in various ways:

print $animal;
print "The animal is $animal\n";
print "The square of $answer is ", $answer * $answer, "\n";

Create...

Create a scalar reference to a non-scalar value

my @worker_array = ("John", "Brown", 32);
my $worker  = \@worker_array;
print $worker;
ARRAY(0x26eebac)

By definition, it isn't actually possible to store a non-scalar value in a scalar variable. However this trick demonstrates good way around that restriction. The same way you might record a person's address, in hopes of gaining access to that person later, you can also record the address (in perl's memory) of an array value, and later get access to the array again. In programming terms the address of a value is called a "reference". In Perl you get a reference to any value by preceding that variable's name with a backslash "\". So in this example we get a reference to an array value and store that reference in the scalar variable $worker. When printed we can see a string representing the address. Why would a reference be useful? One example might be to store a reference to an array as a member of another array, thereby allowing you to create an array of arrays. This becomes much more obvious when you see how to get the actual array value back (see the next trick).

Create a scalar from a reference to an anonymous array

my $worker = ["Sue", "Black", 29];
print $$worker[0];
print $worker->[1];
SueBlack

Here we use another way to create a reference -- the "[...]" wrapper will return an array reference to the list within. The array is called "anonymous" because this method allows us to skip the step of creating a named array variable. The reference is stored in the scalar variable $worker. From the previous trick, recall that a reference is just an address pointing to a value, but to get that value back again requires a little more Perl. In fact there's more than one way to dereference it. First, you may prepend the reference's name with an extra "$" symbol and cause the reference within the scalar to be dereferenced back into its value. Or, perhaps you prefer the arrow -> operator which dereferences the scalar it follows back into the value. In both cases we then print one of the referenced array's elements.

Create a scalar by formatting a number into a string

$t = sprintf ("Winning time: %0.2d:%0.2d:%0.3d", 9, 4, 28);
print $t;
Winning time: 09:04:028

Perl inherited a bit of C-like syntax from its family-tree and the sprintf function is one example. Like its close relative printf this function takes a string with some special formatting syntax embedded within it, and substitutes a list of numbers into the string, applying the formatting as it goes. The s version however doesn't print the result but rather returns a string ready to go into your scalar variable. The formatting is defined within the string like so: "%02.d" where the "%" signals the start of formatting, the "d" indicates that the corresponding number should be converted to a signed integer (in decimal), the ".2" indicates the minimum length of the integer, and the "0" indicates the number should be padded with zeros, if necessary to reach that length. There are many variations on this example available to you so plan on hitting your favorite Perl reference book whenever you need to use this trick!

Create a string by formatting an amount as money

use Locale::Currency::Format;

my $amount  = 10000;
my $dollars = currency_format('usd', $amount, FMT_SYMBOL);
print "Please give me $dollars, thank you.";
Please give me $10,000.00, thank you.

Yet another example of a good module taking care of all the dirty work for you. You could try to write a collection of regexes and symbol look-up tables, but it's already been done for you! Use Tan D Nguyen's module Locale-Currency-Format.

Create a datestamp with todays's year, month, date

$datestamp = sprintf "%02d%02d%02d", 
    ((localtime)[5]%100, (localtime)[4]+1, (localtime)[3]);
print $datestamp;
010407

This is a task that seems simple in concept but looks complex in execution. The idea is to get a little string made up of 3 two-digit numbers representing the current year, month and date. The first task is to get the date values, and we go to the built-in localtime function for that. In a scalar context this function returns a rather long, but nicely formatted date string. In an array context however we get a list of values, the 3, 4, and 5 entries represent the date, month and year respectively. The next task is to do a little math on these values. Since the month is returned as a value between 0 and 11 (for easy use as an array index I suppose) we need to add 1. The year is given as the number of years since 1900, and we want a two-digit representation anyway so we use the modulus operator "%" to get the years remaining when divided by 100. Finally we need to pad any single-digits with zeros to get a two-digit number -- sprintf does that quite nicely. We give sprintf a template string and an array of values, it returns a string made up of those values formatted according to the template string. SEE ALSO: Graham Barr's module Date::Format available at CPAN.org

Create a date string from 30 days ago

use Date::Manip;

my $today = localtime;
my $last_month = DateCalc('30 days ago', $today);
print join '/', UnixDate($last_month, '%Y', '%m', '%d');
2006/11/08

If you have any date manipulation to do, you really should be using a CPAN module. Trying to reinvent all the convoluted logic required for calendar maths can be an interesting project, but a it's a larger task than you probably think. Use Sullivan Beck's Date::Manip module.

Create a less local localtime

$ENV{TZ} = 'EST5EDT';
my $nyc_time = localtime;
print $nyc_time;
Fri Feb 16 09:15:05 2007

The localtime function uses the TZ environmental variable to figure out what "local" is. You are free to tell it to use a different time zone, in this case Eastern Standard Time. Some other possible values: US/Pacific => PST8PDT, US/Mountain => MST7MDT, US/Central => CST6CDT, US/Eastern => EST5EDT, Canada/Pacific => PST8PDT, Canada/Mountain => MST7MDT, Canada/Central => CST6CDT, Canada/Eastern => EST5EDT.

Create a URL encoded string

use URI::Escape;
print uri_escape("snarf & foo!");
snarf%20%26%20foo!

Don't kill yourself trying to comply with all the W3C RFC's regarding URL escaping. Gisle Aas has already done it all for you with his URI::Escape module.

Create a long string by repeating a smaller string

$dottedline = "." x 70;
print $dottedline;
......................................................................

Your computer doesn't mind repetitive tasks so why not let it create repetitive strings for you? The x operator will return a string as if it were multiplied by the following number. This could also be accomplished with a for loop, of course but isn't this syntax so much nicer?

Create a constant scalar which can't be modified

use constant (PI => 3.145926);
print PI;
PI = "cherry"; # fails
3.145926# Can't modify constant item in scalar assignment, near ""cherry";"line 3

There are cases where it doesn't make sense to allow a variable to be set to just anything -- some things in life actually are constant! These types of variables are aptly described as constants. Perl isn't known for being a language of enforcement, but by using the constant pragma as we do here you can create a list of constants which can't be modified elsewhere in your program. Notice that the constant names we use have no type symbol (like $, @, or %) as variables do, and are in fact separate and independent of any variables named "PI", even filehandles. This can be confusing, especially since we used all-caps for the name of the constant, a convention from C. As an example of this notice that on line 2 of our code we are printing the scalar value of the constant "PI", not printing to the filehandle "PI".

Modify...

Modify a number by rounding to n places

$hits = 3;
$total = 9;
$score = sprintf "%.1f", ($hits/$total)*100;
print "score: $score%";
score: 33.3%

Suppose you don't really need the precision of a computer when displaying the result of some calculation which results in a very long answer (like .3333333333...) -- perl can format that into something a little more human-readable using the sprintf function (you might have expected a simple "round" function but there isn't one in Perl). The first argument that you give sprintf is a string that specifies the format you want your result in. Here we specify that we want a float with 1 digit of precision. This results in a score that is correctly rounded to one place after the decimal point. Of course you could change the 1 to some other number and it will work as expected. Note that if you just want to truncate the number down to an integer (by throwing away whatever might be after the decimal point) you can use the easier-to-type int function, but that wouldn't really be rounding then would it? SEE ALSO: Geoffrey Rommel's Math::Round module.

Replace variables in a scalar with their values

my $name = 'John';
my $form = 'Dear $name, I "left" you \$10.';

print eval "qq\0$form\0";
Dear John, I "left" you $10.

When a literal string, wrapped in double quotes, contains variables, those variables are "interpolated," that is translated into their values. But if that same string is itself stored in a variable (perhaps read in from an external source, like a file) then how do you get the interpolation to happen? Simply double-quoting the containing variable only gets you half-way, you must double-quote it twice! The trick shown above does that, by evaluating the variable inside a double-quote, inside a qq() call, another way of "double-quoting." Usefully qq lets you specify whatever delimiter you like, because you must choose a character that won't ever appear in the string itself. In this case I use the null character \0, an unprintable that I know won't be in my data. Be warned that the eval call makes this technique dangerous to use on variables that could possibly contain runnable code. SEE ALSO: Brian McCauley's String::Interpolate module.