#!/usr/bin/perl
# Anything after a pound sign is a comment, ignored by perl,
# except for #! in the first line of a file which identifies
# where the perl program is found.  In this latter case, if
# the perl script file is executable, in Unix/Linux it can be
# tun without explicitly mentioning perl, i.e., myscript.pl
# on the command line will run the script in perl.  (Note: use
# the Unix/Linux command: chmod u+x myscript.pl
# to make the script names myscript.pl executable.)

# "use strict" is recommended; it forces you do declare variables
# (with "my") before using them.  It also does some other
# things to prevent bad code.
# Important: End each line with a semicolon!
use strict;  
use warnings; # this is recommended to warn about bad practices

# Note: This file is based on http://perldoc.perl.org/perlintro.html

# "print" sends stuff to the terminal.  It does not go to the
# next line unless you explicitly include "\n".
# Note that functions can be written with or without the parentheses.
# Text (strings) can be put in double or single quotes (but see
# below for how the results may differ.)
print "Hello, world\n";
print("Function form\n");

# Declare variables (and optionally use "=" to initialize them)
# using the keyword "my".  Precede the name of variable holding
# a single number or string (called a 'scalar") with a dollar sign.
# Nothing distinguishes numeric from string variables.
my $animal = "camel";
# This prints "The animal is $animal".  Inside double quotes
# the dollar sign indicates variable substitution, and so-called
# "escape characters" like "\n" are translated (e.g., "\n" becomes
# the newline character).
print "The animal is $animal\n";
# This prints "The animal is $animal\n".  No substitution is done.
print 'The animal is $animal\n';

# Now print the missing newline.
print "\n";

# Variable naming rules: After the dollar sign, use a letter 
# (or, in special cases, an underscore), followed by optional 
# letters, numbers and underscores.  Variable names are case
# sensitive.  The name can be of any length.

# A numeric example.  The "print" function can take any number of
# inputs, separated by commas.  Some of these can be complex
# expressions like methematical operations or function calls.
my $answer = 42;
print "The square of $answer is ", $answer * $answer, "\n";


## Not available in earlier versions of perl:
##use ActiveState::Handy "ceil";  
## scalar
##my $deci=3.7;
##my $text="Convert $deci to ".ceil($deci)."\n";  # line 22
##print $text;


# Another basic variable type in perl is an "array".  This
# holds any number of ordered elements of any type (including
# other arrays as a single element of a given array).  The at sign
# indicates an array variable.  Use parentheses and commas to
# initialize an array.  Use square brackets and numbers to refer
# to individual elements of an array (zero is the first element).
# When refering to individual elements of an array using square
# brackets, you are refering to a scalar, so the variable naming
# convention requires use of a dollar sign rather than an at sign
# in that context.
my @arr=(3,"DEF",4);
print "Three = $arr[0]\n";
# A period (".") is the concatenation operator (with no space
# between the concatenated elements in the result).
# This prints "ABCDEFGHI" (then goes to a new line):
print "ABC" . $arr[1] . "GHI\n";

# The "foreach" operator succesively assigns each element of
# an array to the special variable "$_", so this line prints
# arr=3
# arr=DEF
# arr=4
print "arr=" . $_ . "\n" foreach @arr;


# (See http://perldoc.perl.org/perlrequick.html for Reg Expr.)
# The "grep function takes a regular expression for its first
# argument and an array for its second argument, then returns
# an array of elements matching the regular expression.
# For this example only elements starting with a number are
# matched (elements 0 and 2).
my @arrnum = grep /^[0-9]/, @arr;
print "arrnum=" . $_ . "\n" foreach @arrnum;

# Any string scalar, even in an array, can be modified using
# the substitution syntax of regular expressions.  Here
# capital "EF" is changed to lower case "ef" (resulting in
# "Def").
$arr[1]=~s/EF/ef/;
print "arr=" . $_ . "\n" foreach @arr;

# Change the "@" to "$#" to get the element number of the last
# element of the array.
print "length of arr is " . (1+$#arr) . ".\n";

# Alternatively, use "@var" in a scalar context to get its
# length: either "my $len = @arr" or just:
print "length of arr is " . @arr . ".\n";

# The third data type in perl is the hash (also known as an 
# associative array).  It holds unordered data pairs, where
# one element of the pair is the "key" used for fast lookup
# and the other element is data of any type (the "value").
# A percent sign ("%") identifies a hash.  One way to set
# elements of a hash is shown below, using parentheses and
# "=>" between the key and value, and commas between the
# elements.  The keys must be unique (no repeats) strings.
# The values can be anything.  Quotes around the keys are
# optional in this context (because they are assumed to
# be strings).
my %pos = (
  apple => 'noun',
  polish => 'verb',
  nail => 'noun',
  red => 'adjective'
);

# Use curly braces ("{}") to get the value for a particular
# key.  Don't use quotes around the key values inside the
# curly braces.
print("Apple is a $pos{apple}.\n");

# Assigning to a non-existent key creates a new entry (but
# be careful, if the key does exist, its value is replaced
# by this syntax).  Here, the dollar sign indicates that
# the value corresponding to this key is a scalar.
$pos{screw}='noun';
print("Screw is a $pos{screw}.\n");

# The qw() function generates a list of quoted words, saving 
# you from the tedium of typing quotes and commas.
# If a list of quoted words is used inside the curly brace
# extraction operator of a hash, the result is a list
# of the values corresponding to the keys on the list.
my @nouns=@pos{qw(apple screw)};  # result is: noun noun
my $nouncount=@nouns;
print "Length=".$nouncount."\n";
print $nouns[0]." ".$nouns[1]."\n";

# The "keys" function makes a list of all of the keys from
# a given hash.  The elements are returned in random order!
my @first2=keys %pos;
@first2=@first2[0,1];
print $first2[0]." ".$first2[1]."\n";

# The "each" function return a list for which each element
# corresponds to one hash entry, and each element is a list
# of the key and the value.
# The syntax "($var1, $var2) = @var3" can be used to separate
# and assign the two sub-elements in each element of $var3
# to user defined named variables (here $var1 and $var2).
while ((my $k, my $v) = each %pos) {
 print "$k is a $v\n";
}

# The "sort" function takes an array and returns a sorted
# version of it.  The "foreach" control element succesivly
# assigns elements of its second argument to the variable
# named in its first argument (or "$_" if the first
# argument is left off).
foreach my $nn (sort keys %pos) {
 print "$nn is a $pos{$nn}\n";
}

#   Subroutines are important for writing good code for larger
# programs.  They are defined using the "sub" keyword followed
# by a name (without a prefix), followed by the code on one or 
# more lines delineated by curly braces.  By convention, the name
# is all lower case.  
#   Generally, you should define the subroutine before calling it,
# or just declare the subroutine (using "sub" and the name without
# any code) before calling it, and then you can define it 
# somewhere below in your code.
#   The perl term "subroutine" includes what other languages
# would call a "function", i.e., they can have input parameters.
#   You can use or not use the parentheses around the arguments
# when calling the subroutine, but using them is more common
# currently.  
#   The arguments set by the user when calling a subroutine
# are available inside the subroutine as the list variable
# "@_".  As usual for a list, you may use "$#_" to get element
# number of the last element of the argument array, and "$_[n]"
# to get the n'th element as a scalar.
sub foo {$_[0]+3}
print "foo(4)=".foo(4)."\n";
sub bar {
    my ($x)=@_;
    return($x+3);
}
print "bar(4)=".bar(4)."\n";
sub cnt {
    my $len = @_;
    return($len);
}
print "Called with " . cnt(3, 5, 7) . " arguments\n";


# "foreach" loops are a common construct for repetitive activities.
# They take the form "foreach variable_name (array_name) {CODE}",
# where "variable_name" is a scalar that takes on successive values 
# from "array_name", and the code inside the curly braces is repeated
# for each value of the array.  If the variable is not pre-defined
# use "my" in front of it as an in-place declaration of its existence.
# Optionally, the variable name can be dropped, in which case the
# code can read the values in "$_".
#   A second form of "foreach" is as a statement suffix, in which
# case the statement is repeated with the variable "$_" set to each
# list element.
my @evens=(2,4,6,8);
foreach my $elem (@evens) {
  $elem += 1;
}
print $evens[$_]."\n" foreach (0..3);
foreach my $odd (@evens) {print $odd."\n";}

# %ENV is a predefined has containing the environment of the
# operating system.  Here, the path is pulled out of that
# hash, then the "split" function is used to break that up into
# components (assumed to be separated by colons).  Split
# takes a scalar string and returns an array made of the sub-strings
# created by splitting on the specified split text.
my $path = $ENV{PATH};
my @paths = split(":", $path);
print "Length of paths is " . @paths . ".\n";
foreach my $item (@paths) {
  print "Item: $item\n";
}

# Splitting on an empty string ("") breaks a string into its
# component characters.  "Join" combines strings in an array
# into a single scalar string with the specified text placed
# between the elements when they are put together.  (When the
# joining text is blank (""), "join" works like the "." 
# concatenation operator.)
my @letters = split "", "ABCDEF";
print join(":",@letters)."\n";
print join(':', split(/ */, 'hi there'))."\n";


#   Files are manipulated using a file handle, which is
# named using the usual variable naming conventions, but
# has no prefix and is conventionally all upper case.  In
# addition you do NOT use "my" to declare file handles.
#   The "open" function opens the specified file (for reading,
# by default) and assigns the result to the file pointer
# ( here, "FIL").
#   The use of "<>" around a file handle, indicates reading
# from the file (into the "$_" variable, by default).  The
# while succeeds if there is a line to read.
#   The "chomp" function removes CR/LF from the end of a 
# string (and operates on "$_" by default).
#   The split/join code here splits each line on spaces and
# re-joins with periods.
my @words;  # not local to while() due to use below
open(FIL, "NowIsTheTime.txt");
while (<FIL>) {
  chomp;
  @words = split / /;
  print join(".", @words)."\n";
}


## switch # Not on older versions of Perl
##use feature "switch";
##my $whch="Howard";
##given($whch) {
##  when (/^S.*n$/) {print "Last name\n";}
##  when (/^H.*d$/) {print "First name\n";}
##  default {print "Neither\n";}
##}
##
##$whch=-4;
###given($whch) {
##  when (2) {print "two\n";}
##  when (\&foo) {print "Not -3\n";}
##  default {print "Neither 2 nor -3\n";}
##}


#   Matching is commonly used in text processing.  Whatever
# matches what is inside the parentheses in a perl regular 
# expression is assigned to numbered variables for use later
# in the program.  
#   The syntax "$var =~m/regular_expression/" returns true
# if the regular expression matches the string and false
# otherwise.  The assignments to $1, $2, etc. are a side
# effect.
#   Here, "\d" refers to any digit and "\W" refers to any
# non-"word" character.  The "+" means 1 on more matches
# (of digits).
my $mystring = "[2004/04/13] The date of this article.";
if($mystring =~ m/(\d+)(\W)/) {
	print "The first number is $1.\n";
	print "The first delimeter is $2.\n";
}

# Here, the "g" suffix to the regular expression stands for
# "global" and means that the process is repeated until
# no more matches are found.  The result is that all
# three numbers (2004,4,13) are stored in the array.
my @myarray = ($mystring =~ m/(\d+)/g);
print "All numbers: ".join(",", @myarray)."\n";

## smart match (http://perltraining.com.au/tips/2008-04-18.html)
##use feature "say";  # OR use feature ':5.10';
##my $x = "foo";
##my $y = "bar";
##my $z = "foo";
##say '$x and $y are identical strings' if $x ~~ $y;
##say '$x and $y are identical strings' if $x ~~ $y;
##my @friends = qw(Frodo Meriadoc Pippin Samwise Gandalf);
##my $name    = "Samwise";
##print $name."'s a friend.\n" if $name ~~ @friends;


# A "reference" is a scalar that holds the "address" of another
# variable.  Without the backslash, "my $wref=@words" would
# store the length of @words into the numeric scalar $wref.
# (See http://perldoc.perl.org/perlreftut.html.)
my $wref=\@words; # (scalar) reference to words from file from above
my $aref=\@arr;
print "Third word directly is ".$words[2].".\n";
print "Third word by reference is ".@{$wref}[2].".\n";

# Anonymous references refer to things that have no other way
# to refer to them.
my $vref=["run", "play", "hide"]; # annonymous reference;
my $href={PA=>"Harrisburg",VA=>"Richmond"}; # annonymous reference;
my @arrayOfArraysPlus1=($wref,$aref,$vref,$href);
print "length of array of arrays=".@arrayOfArraysPlus1.".\n";
print "Third word by array element 0 is ".${$arrayOfArraysPlus1[0]}[2].".\n";

# The operator "->" accesses element in what the array refers to.
print "Third word using -> is ".$wref->[2].".\n";
my $zref=$arrayOfArraysPlus1[0];
print "Third word using zref  is ".$zref->[2].".\n";
print "Capital of VA pulling out the hash is ${$href}{'VA'}.\n";
print "Capital of VA dereferencing the hash is ".$href->{VA}.".\n";
print "Capital of VA is ${$arrayOfArraysPlus1[3]}{'VA'}.\n";
$zref=$arrayOfArraysPlus1[3];
print "Capital of VA using zref is ".${zref}->{'VA'}.".\n";


# nested hash with anonymous hash references
my $variables = {
  scalar => {
    description => "single item",
    sigil => '$',
  },
  array => {
    description => "ordered array of items",
    sigil => '@',
  },
  hash =>  {
    description => "key/value pairs",
    sigil => '%',
  },
};
print "Scalars begin with a $variables->{'scalar'}->{'sigil'}.\n";

# Sockets can read web pages.  The "use" command loads extra parts
# of perl needed for specific uses.
use LWP::Simple;
my $doc=get("http://www.stat.cmu.edu/~hseltman/abc.txt");
chomp $doc;
print join(":",split(/ /,$doc))."\n";


# backreferences: "\1" means match the text from the first group.
my $dupstr = "Now is the time time for all good men";
$dupstr =~ /(\w+)\s+\1/;
print "Duplicated: " . $1 . "\n";


# "Here documents" allow literal embedding of multiline
# text inside a program.
my $hd = <<END;
Here is my
sample
"here" document.
END
my @hda = split /\s/, $hd;
print join("-",@hda) . "\n";

# The sleep function puts the program to sleep for the specified
# number of seconds.  This is used to allow reading the output
# on a Windows system.
sleep 5;
