
Perl solution to Event 2 in the 2008 Winter Scripting Games.
Solutions are also available for VBScript and Windows PowerShell.
This event covered two separate areas of scripting. One was reading from the registry, the other was parsing a string. Let’s take a look at the final answer the Scripting Guys came up with:
use Win32::TieRegistry;
$total = 0;
$tt = 0;
$Registry->Delimiter("/");
@vals = $Registry->{"LMachine/Software/Microsoft/Windows NT/CurrentVersion/Fonts/"}->ValueNames;
for my $val (@vals)
{
$total++;
$x = index($val,"TrueType");
if ($x > 0)
{
$tt++;
print "$val\n";
}
}
print "\nTrueType: $tt\n";
print "Total: $total";
To access the registry in Perl we need to import the classes and functions of the Win32::TieRegistry module. We do this by putting a use statement at the beginning of the script:
use Win32::TieRegistry;
Now that we have that taken care of we can get down to business. One of the requirements for this event was to count the number of true type fonts on the computer; another was to count the total number of fonts. If we’re going to count something, we’ll often need a counter to do that, which is why we’ve started our script by initializing two variables to do our counting for us:
$total = 0; $tt = 0;
Next we have this line of code:
$Registry->Delimiter("/");
We don’t have to put this line in our script, but it can make reading the script easier. As we’re sure you know, registry paths use the backslash (\) to separate keys in a path, like this:
HKEY_LOCAL_MACHINE\Software\Microsoft
The problem with this is that, in Perl, the \ is a special character and can’t be included in a path like this. In order to use the \, we need to “escape” it by adding another \, like this:
HKEY_LOCAL_MACHINE\\Software\\Microsoft
This can get difficult to read as paths start to get longer. To avoid this double-backslash problem, we simply change the delimiter to something that isn’t a special character, such as the forward slash (/). That way we can specify paths like this:
HKEY_LOCAL_MACHINE/Software/Microsoft
Just a nice little bit of convenience and readability.
Okay, we have all preliminaries out of the way, now let’s read from the registry. We gave you a pretty big hint on how to do this in the Scripting Games Tips. Because of that we won’t go into great detail here, but we will walk through it quickly.
In Perl it really takes only one line of code to read a set of values from the registry:
@vals = $Registry->{"LMachine/Software/Microsoft/Windows NT/CurrentVersion/Fonts/"}->ValueNames;
One of the objects that was imported with the Win32::TieRegistry module was the $Registry class. We can use this class to directly link to the registry key we want to work with. We link directly to the key by specifying the key we’re linking to. (Notice the use of LMachine to represent HKEY_LOCAL_MACHINE, and the use of the forward slash delimiter in the path.)
Now take a look at the method at the end of this line of code: ValueNames. By calling this method we retrieve only the names of the values within the specified key, which just happens to be exactly what we want. These values are read into the array @vals.
So we have our array of registry values, which, as we mentioned in the event description, just happens to be the list of fonts on the computer. Now we can start reading through those values. We do that with a foreach loop (note that in Perl you can simply use for rather than the fully spelled-out foreach):
for my $val (@vals)
This loop will loop us through the collection of value names (font names) one at a time.
We also wanted to count the total number of fonts retrieved, so each time through the loop we add one to the counter $total:
$total++;
Note: In Perl, this line: $total++; has identical functionality to this line: $total = $total + 1; |
Now we want to display all the font names. Wait, not all the font names. If you displayed all the fonts you didn’t receive any points for this event. What we really wanted were the true type fonts. It’s pretty obvious which fonts are the true type fonts; they all have (TrueType) appended to their names, like this:
Lucida Bright (TrueType)
That means that, in order to find the true type fonts, we simply need to find the fonts with “TrueType” in their names. We do that by using the index method:
$x = index($val,"TrueType");
As you can see, we pass two parameters to index: the string we want to search ($val) and the substring we’re searching for (“TrueType”). The index method returns the position within a string where the substring we’re searching for starts. If the substring isn’t found, index returns -1. So we check the value of $x in an if statement:
if ($x > 0)
If $x is greater than 0, we found “TrueType” in our font name, so we can display the name of the font. We also want to increment the counter that’s keeping track of the number of true type fonts:
$tt++; print "$val\n";
Once we’ve looped through all the values we print the total number of true type fonts found and the total number of fonts found:
print "\nTrueType: $tt\n"; print "Total: $total";
That’s it, we’re done.