The essence of perl is indeed that of string manipulation - and no tool better than that of the powerful regular expression engine. When understood correctly, this can make quick work of all your string tasks.

At the core of this are four lines. Just four - two of them are rather boring.

  1. Select three separate strings - two from elements, one from endings. Place an 'X' between these as a place holder.
  2. Replace two non-vowels separated by an 'X' with the two non-vowels separated by an 'a'.
  3. Replace a letter followed by an 'X' followed by the same letter again with only one instance of that letter.
  4. Replace all 'X' with nothing (remove all 'X's)

The 'qw' operator in perl is for quote words. This changes a list of words into a list of quoted words removing the need for having quotes around them or commas between the elements. It is understood that words separated by white space are being changed into a list. This is being assigned to an array called 'elements'. The '@' in front of the array says that this is indeed an array (think '@' which kind of looks like an 'a' meaning array - in perl, another name for list). The same is done for the list of words 'ends'.

The scalar ('$' looks like an 's') variable 'name' is being created which is composed of three parts. A scalar variable is something that holds one something. The something is most often a string (of letters), or a number - though there are a few other values that are scalars that are more difficult to explain.

The $name value is built of a member of the @elements list. To use access this list, the [ and ] designates which number value from the list is to be selected ('abig' is in spot 0, 'ad' is spot '1', and so on). The '$' at the start of '$elements' means that we are expecting a scalar from this value (it is possible to stuff lists into lists...). 'rand' is then called with the @elements array as a parameter. When used in a place where a number is expected, an array has the value of the number of elements in the array. When 'rand' is called with a number as a parameter, it returns a real pseudo-random number between 0 and the parameter. This number value is then used as the index into the list again as an integer (rounded down).

The '.' operator is that of string concatenation. People who have touched upon visual basic will recognize this as the & while java types will be more familiar with '+'. Here, an 'X' is placed between elements of the string to designate the boundaries between them (which are tested later).

The heart and soul of this program is three lines. Two really, the third is just cleanup.

The 's///' operator in perl is one that converts what is between the first and second '/' with what is between the second and third '/' with any options following it. This invokes the regular expression engine on the first part and our fun begins.

The [ and ] within a regular expression designate a character class - a set of characters. Here that set is all the characters except the vowels (aeiouy). This is done with the '^' meaning 'not'. Around these character classes are parentheses which stores the values matched into memory - the first item in $1, the second in $2.

The match of "lXr" becomes "lar" - the 'l' is in $1, the 'r' is in $2 and the pattern /([^aeiouy])X([^aeiouy])/$1a$2/g; matches it. This expression runs through all the string (not just the first match - the 'g' is for 'global') and replaces it every time it is found.

The second match is similar to the first, except that now any character can be matched. In regular expressions, the '.' matches any character. Once again the parentheses store the value matched. In the regular expression a '$' means the end of line and to say "that first thing" one has to use a '\' which is a special character in programing worlds to say what follows next is special. The '\1' means that first thing again. Here, we match "letter X same letter" and replace it with just that letter once. Thus 'aXa' is matched, 'a' is in $1, and the string is replaced by just 'a'.

The last thing that needs to be done is the simplest - remove all 'X' from the string, and then print it.


#!/usr/bin/perl

@elements = qw(
  abig ad adri agard agath aid albert alethe and alexi alfred alm
  alt althe alv alvir amand ameli anc andre angel ann anthe antoni
  aren arb arci aric arili arit arlen arlott aronic arri arth ashli
  astasi athsheb atild atri audre august aureli auror avel averli
  bell be bern berth beth beul bonni bridgi brunild carinn cat cecili
  chlo clar claudi col colen consuel corneli cor cosett cyndi dan
  dari darl debor del dolor dulci dorothe dor edn elaid ell ev fann
  fausti feli ferd fifi flor franci fred genev georgi gild gin giov 
  giuli glori gret griseld gunill gwend helg hephzib henri herth
  honori horati huld hermi hest is jessic jeann jemim jo kristi laur
  le len lind lis livi lol lon lor lorn louis luci magd mari mir mil
  mind mon monic nad ness nicol non nor norm ori priscill penel polli
  raciel rebecc regin rhod robert ros sand shirl sib son stell steph
  sus sylvi tar tess tiff trici ver vinni viv wilm yol);

@ends = qw(a abel alison amy chen ie ietty icia ietta ina);


$name =
    $elements[rand @elements] . 'X' .
    $elements[rand @elements] . 'X' .
    $ends[rand @ends];

$name =~ s/([^aeiouy])X([^aeiouy])/$1a$2/g;
$name =~ s/(.)X\1/$1/g;
$name =~ s/X//g;

print ucfirst($name), "\n";