Hey, Scripting Guy! How can I make sure that data entered into an InputBox has the form X:, where X is any alphabetic character? That’s important, because I need to use this string to map logical drives in a script. The script should validate any string such as D:, E:, or F: but flag as incorrect any string such as 9:, !:, 22: etc. I have had limited exposure to regular expressions, and I just can't seem to get the correct pattern.
Hey, DL. If you want to know the truth, there are days when the Scripting Guy who writes this column doesn’t always feel like writing this column. (Shocked? Don’t be; the Scripting Guys have all sorts of deep, dark secrets like that one.) Today isn’t one of those days, however. On the contrary, today the Scripting Guy who writes this column was happy to take time out to write about validating data entered into an input box. That’s because his alternative would be to return to playing Blackjack. And after playing more than 200 hands of Blackjack this morning, he needed a break.
Note. If you’re one of those people who can go to a casino and sit there all day or all night playing cards, well, the Scripting Guy who writes this column tips his hat to you; he couldn’t do it. Instead, after 30 or 40 hands (or was it 130 or 140?) the Scripting Guy who writes this column was ready to throw in the towel.
Of course, unlike an actual casino, there weren’t any waitresses walking around his office bringing him free drinks, either. We suppose that could make a difference.
Of course, many of you are probably thinking, “Why is he playing Blackjack? Is the Scripting Editor running an illegal gambling ring out of her office?” Well, as a matter of fact, she is. However, she won’t let the Scripting Guy who writes this column go in there; instead she just calls the bouncer, all the while muttering something about keeping out the riff-raff. (Which doesn’t make much sense; after all, she lets Peter and Dean go in there.)
Instead, the Scripting Guy who writes this column was simply scoring Event 10 in the 2008 Winter Scripting Games (Advanced Division), an event that required competitors to write a script that could play a hand of Blackjack.
Note. If you’re torn between entering the actual Winter or Summer Olympics or the 2009 Winter Scripting Games, we might note that, in the Scripting Games, you get to do things like play Blackjack. In the Olympics, you get to do things like run a marathon. It’s up to you.
At any rate, for all you Scripting Gamers anxious to see your final scores, well, we’re getting there; for that matter, we might even be there by the time you read this column. In fact, we’re close enough now that we figured we could take time out to show everyone how to verify that a valid drive letter was entered into an input box:
Set objRegEx = CreateObject("VBScript.RegExp") objRegEx.Global = True objRegEx.Pattern = "[d-zD-Z]:" Do While True strSearchString = InputBox("Please enter the drive letter:", "Drive Letter") If strSearchString = "" Then Wscript.Quit End If If Len(strSearchString) = 2 Then Set colMatches = objRegEx.Execute(strSearchString) If colMatches.Count > 0 Then Exit Do End If End If Loop Wscript.Echo "Your drive letter is " & strSearchString & "."
Let’s see if we can figure out what’s going on here. (With the Scripting Guys, that’s almost always a good question.) We start out by creating an instance of the VBScript.RegExp object; this is the object that enables us to use regular expressions within a VBScript script. After creating an instance of RegExp we assign values to two of the object’s properties. For one, we set the Global property to True; this tells the script that we want to search for all instances of the target text. In this case, the Global property doesn’t really matter; there will be, at most, only one match (that is, one drive letter) for us to find anyway. In general, though, setting Global to True is a good thing; usually you want to find all the instances of something, not just the first instance.
Our next property, Pattern, is a little more interesting. (Although we aren’t saying that the Global property isn’t interesting. We would never say a thing like that!) The Pattern property is where we specify the text we want to find. What text do we want to find? This:
We won’t go through the ins and outs of regular expression syntax in today’s column; for an introduction to regular expressions you might take a peek at our TechNet Magazine column on the subject. In a nutshell, this regular expression can be parsed like so: First, find any of the characters specified within the square brackets ([ ]). Square brackets allow you to specify a set of characters; if any one of those characters is found then you have a match.
So what characters are we looking for? Well, it could be any character in the range d-z.; that’s all the lowercase letters from d to z. Alternatively, it could be any character in the range D-Z; that’s all the uppercase characters from D to Z. P, Q, R, s, t, and u would all results in matches; A, B, and c would not.
Note. Why D through Z (or d through z)? That’s easy: you can’t map drives using the letters A, B, or C (or their lowercase equivalents).
In other words, the first character must be a letter (uppercase or lowercase) from D to Z. That letter must then be followed by a colon (that’s what the : is for). As DL wished, D:, E:, and, F: will be considered valid input; 9:, !:, and 22: will not.
After defining our regular expression pattern we next set up a Do loop designed to run forever and ever. (Or at least as long as True is equal to True.) Inside that loop, the first thing we do is use this line of code to display an input box that prompts the user to enter a drive letter:
strSearchString = InputBox("Please enter the drive letter:", "Drive Letter")
The input box will remain onscreen until the user clicks either the OK button or the Cancel button. If the user clicks OK, the value he or she typed into the box will be stored in a variable we named strSearchString. If the user clicks Cancel, then strSearchString will be set to an empty string.
Suppose the user does click Cancel. In that case, we’re assuming that they don’t want to map a drive after all. With that in mind, we use this block of code to see if strSearchString is equal to an empty string; if it is, we then call the Wscript.Quit method to terminate the script:
If strSearchString = "" Then Wscript.Quit End If
If strSearchString is not empty our next task is to make sure that there are only two characters in the string (you can’t map a drive to, say, drive ABCDE:). Although we could have created a more-complicated regular expression to check for string length we thought it would be easier to just let VBScript’s Len function take care of it for us:
If Len(strSearchString) = 2 Then
If the string length (number of characters) is anything other than 2 we’re simply going to loop around, display another input box, and prompt the user to try again. If the string length is 2, however, then we use this line of code to actually perform our regular expression search:
Set colMatches = objRegEx.Execute(strSearchString)
If any instances of the target text (that is, one of the letters D through Z, followed by a colon) are found then those instances are stored in a collection we named colMatches. How are we supposed to know if any matches were found? That’s easy; we just check the Count property, which tells us the number of items in the collection:
If colMatches.Count > 0 Then
If the Count is greater than 0 that means we have a valid drive letter; in that case, we call the Exit Do statement to exit our Do loop. We then simply echo back the drive letter:
Wscript.Echo "Your drive letter is " & strSearchString & "."
If the Count equals 0 that means the “drive letter” that was entered was invalid; for example, maybe the user entered $:. If that’s the case we again go back to the top of the loop, display another input box, and try the whole thing all over again.
Believe it or not, that’s all there is to it.
In case you’re wondering, the Scripting Guy who writes this column didn’t keep track of his Blackjack wins and losses. He actually started to do that, but after he lost 6 of the first 8 games he figured that was silly.
Although, come to think of it, maybe that wasn’t his fault; maybe those scripts were all poorly-written. Sure, that must be it: the Scripting Guy who writes this column didn’t fail, the scripts failed. You know what? We’ll see everyone tomorrow, right now we have to go back and change a bunch of 10s to 0s.
Note to Scripting Games competitors. Take it easy; we’re just joking.