2008 Winter Scripting Games

Solution to Advanced Windows PowerShell Event 9: You're Twisting My Words

Event 9 Solution


Windows PowerShell solution to Event 9 in the 2008 Winter Scripting Games.

Solutions are also available for VBScript and Perl.

*

You’re Twisting My Words


As a general rule in these Scripting Games, we found the Windows PowerShell scripts a little bit easier to write than the VBScript scripts. (We found the Perl scripts the hardest to write, but there’s a good reason for that: neither of the Scripting Guys know anything about Perl.) In the case of this event, however, the PowerShell script proved a tiny bit trickier to write than its VBScript counterpart. Why? Well, both VBScript and Perl have functions that will reverse all the characters in a string; as near as we could tell, however, PowerShell has no similar function. (There’s no doubt something hidden deep within the bowels of the .NET Framework, but we didn’t have time to go looking for it.)

What that meant, of course, was that we had to come up with a way to “manually” reverse the characters in a string. Were we able to devise such a method? We’re about to find out:

$strContents = Get-Content "C:\Scripts\Alice.txt"
$strContents = $strContents.split(" ")

for ($i = 0; $i -le $strContents.Length - 1; $i++) 
    {
        $strWord = $strContents[$i]
    
        $b = ""
        for ($x = $strWord.length - 1; $x -ge 0; $x--) 
            {$b = $b + ($strWord.substring($x,1))}

        $strContents[$i] = $b
    }

$strNewContents = [string]::join(" ", $strContents)
$strNewContents

As you can see, there’s really not a lot to this script; in fact, had we chosen to use smaller variable names we could have reduced the total number of keystrokes required to type this script to less than 250. Nevertheless, this one was a tiny bit tricky, and we know that some people were stymied from the very start; they weren’t sure how to even begin to attack the problem. With that in mind, let’s walk through the code and see how it works.

To kick things off, we use the Get-Content cmdlet to read the text file C:\Scripts\Alice.txt. Because Alice.txt consists of a single line (albeit a long one) with no line breaks, that means the beginning portion of the variable $strContents will look like this:

'Curiouser and curiouser!' cried Alice (she was so much surprised,

That’s nice, but it doesn’t help us come with a solution for this event. Therefore, no sooner do we read in the text file then we use this command to split the value of that file into an array:

$strContents = $strContents.split(" ")

As you can see, when we call the split method we tell the script that we want to split the file on each blank space. Why split the file on each blank space? Because then our array $strContents will look something like this, with each item in the array representing a single word (remember, we’re counting punctuation marks as part of the word):

'Curiouser 
and 
curiouser!' 
cried 
Alice 
she 
was 
so 
much 
surprised,

So does that help us come up with a solution to this event? You bet it does. After all, our task here is to reverse the characters in each word while keeping those words in the same order. (Which is why we can’t simply reverse the entire contents of the text file.) Well, guess what? We’ve now managed to isolate the individual words, all the while maintaining the order of those words. ('Curiouser is still the first word, and is still the second word, etc.) Our next step is to take each of those individual words and reverse all the characters.

With that in mind, we set up a for loop that loops through all the items in the array $strContents, beginning with item 0 (the first item in the array) and ending up with Length – 1, the last item in the array. (The last item in an array will always have an index number one less than the total Length of the array; that is, an index number one less than the total number of items in the array. That’s because the first item in an array has an index number of 0 rather than an index number of 1.)

Inside this loop we grab the value of the first item in the array (item $i) and store that value in a variable named $strWord:

$strWord = $strContents[$i]

After we set a “holder” variable named $b to an empty string ($b = ""), we then set up another for loop, this one starting at the Length of the item minus 1 (in other words, starting with the index number of the last item in the array) and then counting down from that value to 0:

for ($x = $strWord.length - 1; $x -ge 0; $x--)

Inside this second loop we execute just one line of code:

$b = $b + ($strWord.substring($x,1))

What are we doing here? Well, here we’re building up the string value $b, starting with the last letter in the word and methodically working our way to the first letter in the word. For example, take the very first word in the array: ‘Curioser. This line of code tells PowerShell to return a substring (hence the use of the substring method) of this word. That substring should start at the $x-th letter (the last letter in the word) and should consist of just one character. Thus the first time through the loop $b will be equal to this:

r

After decrementing $x by 1 we try again, this time grabbing the next-to-last letter and appending that character onto the end of $b; that makes $b equal to this:

re

We continue down that path until we’ve added each character (in inverse order) to $b. At that point $b will be equal to this:

resuoiruC'

Which is just exactly what we wanted: a backwards version of the word ‘Curioser.

After assigning that value back to the original array item ($strContents[$i] = $b) we then repeat this process with the next word in the array. Eventually we’ll end up with an array that looks like this:

resuoiruC' 
dna 
'!resuoiruc 
deirc 
ecilA 
ehs( 
saw 
os 
hcum 
,desirprus

After we’ve reversed all the words we use the join method to combine all the array items into a single string value, separating each of these items (words) with a blank space:

$strNewContents = [string]::join(" ", $strContents)

All that’s left now is to echo back the value of $strNewContents, and bask in the adulation of our peers and co-workers:

resuoiruC' dna '!resuoiruc deirc ecilA ehs( saw os hcum ,desirprus that
rof eht tnemom ehs etiuq togrof woh ot kaeps doog ;)hsilgnE won' m'I 
gninepo tuo ekil eh t tsegral epocselet taht reve !saw ,eyb-dooG '!teef 
rof( nehw ehs dekool nwod ta reh ,teef yeht demees ot eb tsomla tuo fo 
,thgis yeht erew gnitteg os raf .)ffo  ,hO' ym roop elttil ,teef I 
rednow ohw lliw tup no ruoy seohs dna sgnikcots rof  uoy ,won ?sraed m'I 
erus _I_ t'nahs eb !elba I llahs eb a taerg laed oot raf ffo ot elbuort 
flesym tuoba :uoy uoy tsum eganam eht tseb yaw uoy ;nac tub-- I tsum eb 
dnik ot ',meht thguoht ,ecilA ro' spahrep yeht t'now klaw eht yaw I 
tnaw ot !og teL em :ees ll'I evig meht a wen riap fo stoob yreve 
'.samtsirhC

Top of pageTop of page