Perl Page #4: Programming Patterns


There's strictly no warranty for the correctness of this text. You use any of the information provided here at your own risk.


Contents:

  1. Page Description
  2. Declaring Multiple Variables in One Line
  3. Using "qw()" to quickly build Lists
  4. Cycling through the Element-Numbers of a List
  5. Check, if a String Contains Only Digits
  6. Contents and Length of the List "@ARGV"
  7. Using the shift-Function to Access the Arguments inside Functions
  8. Passing Lists or Hashes to Functions as References
  9. Multi-Line Comments
  10. Handling Longer Strings. Socalled "Here-Documents"
  11. Variables inside Regular Expressions: \Q and \E
  12. "__DATA__" or "__END__"
  13. sort, lc and uc don't work in place
  14. Data::Dumper
  15. Further Reading


1. Page Description

This site lists recurring questions and patterns, when programming Perl, especially in an object-oriented way as described on my other page.
It addresses people who already know the basics of Perl-programming.


2. Declaring Multiple Variables in One Line

If you want to declare multiple "my"-variables in one line, separate them with commata and put round brackets around them:

#!/usr/bin/perl

use warnings;
use strict;

my ($i, $u, @a, @b);

If you want to declare global variables, use this line:

use vars qw($i $u @a @b);


3. Using "qw()" to quickly build Lists

You can use the qw-operator to quickly build a list from elements. The elements have to be written without quotation marks and have to be separated by space characters:

#!/usr/bin/perl

use warnings;
use strict;

my @a = qw(Hello good World);
for my $i (@a) {
    print "$i\n";
}


4. Cycling through the Element-Numbers of a List

To cycle through the element-numbers of a list, you can use this pattern:

#!/usr/bin/perl

use warnings;
use strict;

my @a = qw(Hello good World);
for my $i (0 .. $#a) {
    print "$i \t $a[$i] \n";
}

Notice, that "$#a" is the "number of elements of @a minus 1". For whatever reason they build that into Perl.


5. Check, if a String Contains Only Digits

#!/usr/bin/perl

use warnings;
use strict;

my $a = "214314";

if ($a =~ /\D/) {
    print "Contains something else than digits.\n";
} else {
    print "Only digits. String contains a number.\n";
}


6. Contents and Length of the List "@ARGV"

"@ARGV" is the list, that contains the options, passed to the Perl-script on the command-line.

"@ARGV" doesn't contain the name of the script as the first element (as Python's "sys.argv" does). Therefore, "$#ARGV" is -1, if the user didn't pass any option to the script.


7. Using the shift-Function to Access the Arguments inside Functions

In Perl, there are five functions to add elements to lists or withdraw elements from them:

  1. push: Adds an element at the end of the list.
  2. pop: Withdraws an element at the end of the list and returns it.
  3. shift: Withdraws an element at the beginning of the list and returns it.
  4. unshift: Adds an element at the beginning of the list.
  5. splice: Manipulates elements inside the list.

When you call a function, in Perl all arguments are automatically passed in a single list called "@_":

#!/usr/bin/perl

use warnings;
use strict;

sub myFunction {
    for my $i (@_) {
        print "$i\n";
    }
}

myFunction("Hello", "World");

If you want to assign variable-names to the arguments, you have to get them from this special array. If the shift-function is called without any parameter, Perl assumes, that the array "@_" is meant. So you can extract the arguments inside the function like this:

#!/usr/bin/perl

use warnings;
use strict;

sub myFunction {
    # Short for "my $a = shift(@_);":
    my $a = shift;
    my $b = shift;
    print "$a\n";
    print "$b\n";
}

myFunction("Hello", "World");


8. Passing Lists or Hashes to Functions as References

At first sight, the mechanism explained above makes it difficult to pass scalar variables and lists or hashes to functions at the same time.
If you know, that the first element of "@_" represents a scalar variable, and the rest of "@_" represents a list, you could shift the first element of "@_" away and assign the rest to a list-variable.

But there's a more elegant solution: You can pass references to lists or hashes to the function and dereference them in a single line. Here's an example:

#!/usr/bin/perl

use warnings;
use strict;

sub myFunction {
    my $a = shift;
    my @b = @{shift(@_)};
    for my $i (@b) {
        print "$i\n";
    }
}
my $a = "test";
my @b = ("Hello", "World");
myFunction($a, \@b);

The line of the dereferencing

my @b = @{shift(@_)};

may look a bit ugly, but it's rather straight-forward:
"shift(@_)" extracts the list-reference from "@_", then "@{listref}" dereferences it. The variable "@b" is assigned to the resulting list.


9. Multi-Line Comments

The best practice for creating multi-line comments is probably this one:

=begin comment

    This is a comment, that is longer than one line.
    Such comments are for example used to describe
    the features of a program at the beginning of the code.

=end comment

=cut


10. Handling Longer Strings. Socalled "Here-Documents"

It may be useful to put longer strings, that contain a lot of quotation marks, inside q() or qq().
q( ... ) is similar to ' ... ',
qq( ... ) is similar to " ... ".
Example:

#!/usr/bin/perl

use warnings;
use strict;

my $string = qq(This is one of Perl's features for long strings.
The string is longer than one line and contains "quotation marks".
But you don't need to write backslashes in front of them.
If you use qq(), there also is \t interpolation.\n);

print $string;

You can also use socalled "here-documents" in Perl.
To do that, you define a variable with "<<" and then a sequence of characters, like "END_MESSAGE" or "HERE" for example. After that, the following characters are defined as a string, which ends at another occurrence of the defined sequence of characters:

#!/usr/bin/perl

use warnings;
use strict;

my $message = <<'END_MESSAGE';
This is another string,
that is longer than one line.
END_MESSAGE
     
print $message;

For comments, it still may be best to use "#" before each line.


11. Variables inside Regular Expressions: \Q and \E

You can use scalar variables within regular expressions.
But if you just use something like

if ($a =~ /$b/) {...}

variable $b will be interpolated. That means, if $b contains characters, that have a special meaning in regular expressions (such as "*", "." or "!") they will be interpreted with that meaning.
That may not be, what you want, if you literally want to search for "Hello, there!" for example. To suppress the interpolation of $b, you have to put it between "\Q" and "\E" inside the regular expressions (which may seem a bit strange at first, but you'll get used to it). Here's an example:

#!/usr/bin/perl

use warnings;
use strict;

my $a = "House";
my $b = "^H";

if ($a =~ /$b/) {
    print "String starts with a \"H\".\n";
}

if ($a =~ /\Q$b\E/) {
    print "'^H' found in string.\n";
} else {
    print "Substring '^H' not found in string.\n";
}


12. "__DATA__" or "__END__"

Text after the word "__DATA__" or the word "__END__" is ignored as Perl-code (so that the words indicate the end of the actual script), but can be read in as data, using the built-in filehandle called "DATA":

#!/usr/bin/perl

use warnings;
use strict;

my @a = <DATA>;
for my $i (@a) {
    print $i;
}
close(DATA);

__END__
This is one of Perl's features for data, such as long strings.
The data consists of several lines, that can be read into a list.
It can be processed afterwards.


13. sort, lc and uc don't work in place

Functions like sort, lc (lowercase) and uc (uppercase) don't work in place. So you have to reassign the variable like in:

@a = sort(@a);


14. Data::Dumper

The module "Data::Dumper" is used to print the contents of more complex data-structures, such as "Lists of Lists", "Hashes of Hashes" (HoH) and such:

#!/usr/bin/perl

use warnings;
use strict;

use Data::Dumper;

my %h = ( a => ["z", "x", "y"],
          b => "test",
          c => { d => 1,
                 e => 2,
                 f => 3 } );

print Dumper(\%h);

"Dumper" is imported into the script's namespace. It is called with a reference to the variable to be printed (otherwise it would see the parts inside the variable as separated variables).

"Data::Dumper" can also be used to print the contents of objects.


15. Further Reading

My little series about Perl continues with "Perl Page #5: Tips and Tricks".



Email: hlubenow2 {at-symbol} gmx.net
Back