pmasiar has one on Python, I will have one on Perl (any Ruby addicts here?)
One of the things that people complain about is Perl being unreadable. Why it can be true, it depends on the coder's habits and mindset.
Perl is as unreadable as a terminal is unusable. Think about how you learned about various simple commands (ls, cd, man, grep, awk ...), you either read it somewhere or someone told you or you transfer some knowledge you had from somewhere else (in which case #1 or #2 probably happened).
Here is an example of taking readable Perl code and making it unreadable:
Code:
open $file, "/etc/passwd" or die$!;
while ($line = <$file>) { #read in a line from $file and store it in $line
@record = split /:/, $line #split every line on colons and put it into record(note the array sigil)
print "user: ";
print $record[0]; #print the username
print "\t\thome directory: ";
print $record[5]; #print the home directory
print "\n";
}
close $file;
Readable, no?
Here's the "unreadable" kind
Code:
open $passwd, "/etc/passwd";
%_ = map { /^(.*?):(?:.*)+:(.*?):.*?$/gis } <$passwd>;
map { print "user: $_\t\t\thome directory: $_{$_}\n" } keys %users;
close $passwd;
Now to explain it:
Since Perl and Python can be used for functional programming (ie: Scheme, Haskel type), they have a map function which takes a block of code and applies it to a list (to every item in the list). Map sets the $_ variable to the item it is applying the block to.
Map takes the regular expression and applies it to every line in the file (<> fetches a line from an input/file stream), then map takes the regex and applies it to the line.
The Regex (pre syntax got their start in awk):
^ means beginning of the line
$ means the end of the line
stuff surrounded by parenthesis is to be grouped/extracted, when it is extracted, the first item gets put into $1, second into $2, and so on until $9 (perl can't hande more than 9 matches which is a limitation which I haven't met yet in practice), ?: in the beginning of parenthesis tells perl to not extract this grouping.
period/dot by itself means any printable character
* means 0 or more of the character
? means to not be greedy when matching (grab as few as possible)
+ means 1 or more of the character (a+ is same as aa*)
the matching operation is
STRING =~ m/PATTERN/FLAGS;
but when you leave out the STRING (which can be a variable), it is assumed by perl that you mean $_ (which is what map sets on every iteration). Map returns the list value of every "run" (unless you force scalar context)
When the regex matches the line, the first stuff before the colon gets put into $1 (the username) and $2 becomes the home directory.
at the end of map, it returns a list composed of of the $1 and $2 ($1,$2,$1,$2, ...), a hash in Perl is just a key,value,key,value list (array). So perl maps the list returned by map onto a hash.
next map simply prints the key and the hash value at that key for all keys in the hash
an example of how map can substitute a loop:
C-like Perl array iteration
Code:
@array = (1,2,3,4,5,6,7,8,9);
for ($i = 0; $i <= $#array; $i++) { ### $#array is the index of the last set element in @array (8 in this case)
print $array[$i] . "\n";
}
Perl iteration
Code:
@array = (1,2,3,4,5,6,7,8,9);
for (@array) {
print $_ . "\n";
}
single line version of the above
Code:
@array = (1,2,3,4,5,6,7,8,9);
print $_ . "\n" for(@array);
}
the map version
Code:
@array = (1,2,3,4,5,6,7,8,9);
map { print $_ . "\n" } @array;
NOTE: @array is explicitly declared for clarity purposes
NOTE2: when you are matching only 1 thing in a string to be used somewhere, usually you would use
Code:
$item = $1 if ($input =~ /PATTERN/);
which is clearer than doing the "proper" if block.
Bookmarks