Previous Page
Next Page

Parsing Passed Text into an Array

In this example, you work through a script that creates a dynamic array used to hold information parsed from the Windows 2003 setup log file, Setuplog.txt.

More Info

When we parse text, we are looking through the text to identify word strings, numbers, or even case sensitive letter matches using the InStr function. This technique is foundational to working with text files, log files, and even event logs. You can use multiple InStr functions in the same script to come up with complex test scenarios. For advanced pattern matching, you can use Regular Expressions, which are documented in the Platform SDK (\My Documents\Microsoft Press\VBScriptSBS\Resources\Scripts56.chm).


One issue to note: If you're working on an upgraded version of Windows 2003, your Setuplog.txt file is contained in the WINNT directory. If you're working with a fresh installation, the Setuplog.txt file is contained in the Windows directory. The reason for this is that beginning with Microsoft Windows XP, the name of the default Windows directory was changed from WINNT to Windows. However, in an upgrade, the Windows directory cannot be renamed without potentially breaking applications.

In our script, SearchTXT.vbs, you create a dynamic array and set its initial size to zero. You next make a connection to the file system object and open the Setuplog.txt file, located in the Windows directory (this path may be edited if required), for reading. Once the Setuplog.txt file is opened for reading, you define a search string of "Error" and use the InStr command to look through each line. If the string "Error" is found on the line being examined, the line with the error is added to the array. You then increment the next element in the array in case you find another line with the string "Error" in it. After you go through the entire text file, you use a For...Next loop and echo out each element of the array. The script concludes with a friendly "all done" message. The code for SearchTXT.vbs follows.

SearchTXT.vbs

Option Explicit
On Error Resume Next
Dim arrTxtArray()
Dim myFile
Dim SearchString
Dim objTextFile
Dim strNextLine
Dim intSize
Dim objFSO
Dim i
intSize = 0
myFile = "c:\windows\setuplog.txt" <'>Modify as required
SearchString = "Error"
Const ForReading = 1
Set objFSO = CreateObject("Scripting.FileSystemObject")
Set objTextFile = objFSO.OpenTextFile _
  (myFile, ForReading)
Do until objTextFile.AtEndOfStream
  strNextLine = objTextFile.ReadLine
  if InStr (strNextLine, SearchString)then
   ReDim Preserve arrTxtArray(intSize)
   arrTxtArray(intSize) = strNextLine
   intSize = intSize + 1
  End If
Loop
objTextFile.close
For i = LBound(arrTxtArray) To UBound(arrTxtArray)
   WScript.Echo arrTxtArray(i)
Next
WScript.Echo("all done")

Header Information

The Header information section of SearchTXT.vbs contains few surprises at this juncture. The important aspect in this section is the listing of all the variables contained in SearchTXT.vbs. This declaring of the variables provides a blueprint for understanding the script. Each variable and its use is listed in Table 5-1. The Header information section of the script is listed here:

Option Explicit
On Error Resume Next
Dim arrTxtArray()
Dim myFile
Dim SearchString
Dim objTextFile
Dim strNextLine
Dim intSize
Dim objFSO
Dim i

Table 5-1. Variables declared in SearchTXT.vbs

Variable

Use

arrTxtArray()

Declares a dynamic array

myFile

Holds the file name of the file to open up

SearchString

Holds the string to search for

objTextFile

Holds the connection to the text file

strNextLine

Holds the next line in the text stream

intSize

Holds the initial size of the array

objFSO

Holds the connection to the file system object

i

Used to increment intSize counter


Reference Information

The Reference information section of the script is used to assign values to many of the variables that are declared in the Header information section. The Reference information section of SearchTXT.vbs follows.

intSize = 0
myFile = "c:\windows\setuplog.txt"
SearchString = "Error"
Const ForReading = 1
Set objFSO = CreateObject("Scripting.FileSystemObject")
Set objTextFile = objFSO.OpenTextFile _
  (myFile, ForReading)

The variable intSize is used to hold the value of the initial size of the dynamic array used in this script. It is set to zero because you do not know how many items you will have in your dynamic array. You start with the value of zero, and then you later increase the array to the required size as you read through the log file. A different approach would be to create an array that is much larger than you think you'd need and then populate the array with the items gathered from the log file. However, there are at least two problems with this approach:

  • Creating an array that is too large wastes memory resources

  • Creating an array that is too large results in too many elements that have a zero value

The myFile variable is assigned to the physical location of the log file you want to parse. In this instance, you are looking at the Windows Server 2003 setup log file contained in the Windows directory. This is one modification you will need to make to your scriptchanging the location and name of the log file you want to parse. By creating a variable called myFile, and by assigning it to a log file in the Reference information section of the script, you make it easy to modify the script for future use. By simply changing the file you want to parse, you can use this script to peruse many different log files.

SearchString is the variable that holds the string of letters you want to glean from the log file. As the script currently stands, you are searching for the word "Error" in the Windows Server 2003 setup log file. By searching for "Error," you create an array that holds all the errors that occurred during the installation of the Windows Server 2003 server.

You create a constant called ForReading and set it to the value of 1. Then the next step is to create a FileSystemObject and use the ForReading constant to open the log file. When you open a text file using a FileSystemObject, you must tell VBScript whether you're going to open the file and read from it, or open the file and write to it. In your script, you need only to be able to read from the file to find the lines containing the word Error.

Note

For more information about creating and using constants, refer to Chapter 2, "Looping Through the Script."


You now use the Set command to assign the variable objTextFile to be equal to the command that opens the text file for reading. Here is the syntax for this command:

Set

New variable

Command

File name

Read or write

Set

objTextFile

objFSO.OpentextFile

myFile

ForReading


Worker Information

The Worker information section of the SearchTXT.vbs script, shown in the following code, is where you create a text-processing engine. This engine is made up of the following components:

  • Do Until...Loop

  • If...Then loop

  • ReDim Preserve

Do Until objTextFile.AtEndofStream
  strNextLine = objTextFile.ReadLine
  If InStr (strNextLine, SearchString) Then
    ReDim Preserve arrTxtArray(intSize)
    arrTxtArray(intSize) = strNextLine
    intSize = intSize + 1
  End If
Loop
objTextFile.Close

Do Until...Loop is used to walk through the text stream that comes from the connection to our setup log file. The Do Until structure controls the entire process and will continue working until it comes to the end of the data stream (which incidentally occurs when you reach the bottom of the text file).

The variable strNextLine is assigned to the line of text that comes from the text file when you use the ReadLine command on objTextFile. (Remember that you defined objTextFile to be textStreamObject you get back from the setup log file. You do this by using the read-only version of the OpenTextFile command in the Reference information section of the script.)

You use an If...Then structure to look through strNextLine for the value contained in the variable you called SearchString. In the Reference section, you assigned the value of "Error" to the variable SearchString. You use the InStr command to search strNextLine for the text string "Error." The InStr command has the following syntax:

InStr

Starting position (optional)

String being searched

String searched for

Compare mode (optional)

InStr

 

strNextLine

SearchString

 


When using InStr, the starting position is the first character in the text string to be searched. It is important to remember that the InStr command is not zero-based. A position that is actually 38 spaces away will be reported as 38. The optional starting position field of the InStr command is useful when parsing certain log files that begin each line with a time stamp or other information that makes the file difficult to parse. By skipping past the time stamp, you can parse the line more easily.

Note

Many of the commands you use in VBScript are, for whatever reason, zero-based, which means that you start counting at zero. But now you come to InStr, which is not zero-based. A position that is 12 spaces away will be reported as 12. Forget this fact, and your scripts will act really strange.


If the InStr command finds the search text in the search string, you use ReDim Preserve to expand the array by one element. ReDim Preserve actually performs two tasks. The first is to resize the array, and the second is to make sure you don't lose any data when the array is resized. The arrTxtArray(intSize) = strNextLine line adds the value contained in strNextLine to the arrTxtArray element identified by the intSize variable. The intSize = intSize + 1 construct increases the intSize variable by 1. You'll use this variable to add one more element to your array when the InStr command finds an additional line containing the word "Error" in the text string.

When you reach the end of the data string, you use End If to end the If loop and the objTextFile.Close command to close the text file. This closing step is not really required, because the text file automatically closes when the program quits; however, this step is considered good practice and can prevent potential file-locking problems in the future.

Output Information

After you load the array with the information gathered from the setup log file, you really have accomplished only half of the task. This is because constructing an array and not using it is pretty well useless. In this script, you're going to simply echo out the lines found that contain the word "Error" in them. In many cases, echoing the errors out is sufficient. In later chapters, you'll learn how to save this information to a text file for future manipulation if desired. Because your script is modular in its design, you could easily replace this Output information section with one that saves to a text file or creates a Web page, or one that creates and sends an e-mail.

You use a For...Next loop to work through the lower boundary and the upper boundary of your dynamic array. Once you get to each new element in the array, you use the WScript.Echo command to print to the screen the data contained in that element of the array. Then use the Next command to go back and read the next element in the array. You continue to do this until you reach the upper boundary of the array. Once you reach the end of the array, you use WScript.Echo to let yourself know that the script completed successfully. This section of the script is listed here:

For i = LBound(arrTxtArray) To UBound(arrTxtArray)
  WScript.Echo arrTxtArray(i)
Next
WScript.Echo("all done")

Quick Check

Q.

What is the advantage of using a dynamic array?

A.

You can expand a dynamic array when a new element is needed. This saves memory and is more efficient.

Q.

How is ReDim Preserve used?

A.

ReDim Preserve is used to resize a dynamic array while ensuring that the data contained in the array is not lost.


Use the InputBox function and separator line function

1.
Open \My Documents\Microsoft Press\VBScriptSBS\ch05\MultiValuesSearch.vbs in Microsoft Notepad or your script editor of choice. Save the script as YourNameSearchTXTMultiValues.vbs.

2.
Declare three new variables to be used for the InputBox function. The variables are: strPrompt, strTitle, and strDefault. This is seen below:

Dim strPrompt,strTitle,strDefault 'used for input box

3.
In the Reference section, assign value to strPrompt. The value assigned to strPrompt will appear in the gray section of the input box. It should tell the user to enter values to search for, and it should specify the name of the text that will be searched. It will look something like the following:

strPrompt = "Enter error words to search for in: " & _
          VbCrLf & myFile

4.
Under the entry for strPrompt, assign value to the strTitle variable. This will appear at the top of the input box and should inform the user of the purpose of the input box. My entry looks like the following:

strTitle = "Error locator"

5.
Under the entry for strTitle, assign value to strDefault. This will be the multiple strings searched for in the text file if the user just presses Enter and does not edit the input box. Make sure to not put spaces between the comma-separated values. Otherwise, when the Split function breaks the line into an array, the InStr function will search for a space as well as the value. My entry looks like the following:

strDefault = "Error,failed,unable to,was NOT"

6.
Modify the searchString variable so that it is equal to what is returned from the InputBox function. It will look like the following:

SearchString = InputBox(strPrompt,strTitle,strDefault)

7.
Save and run the script. You should see an input box appear, and when you press Enter, the script should search for the values you entered for strDefault. If this does not happen, compare your script to \My Documents\Microsoft Press\VBScriptSBS\ch05\SearchTXTMultiValues.vbs.

8.
Now let's clean up the output just a little to make it easier to read. To do this, we will use the funLine function. Copy the function from the \My Documents\Microsoft Press\VBScriptSBS\Utilities\FunLine.vbs file. The function is seen below. You will paste it at the very bottom of your script.

Function funLine(lineOfText)
Dim numEQs, separator, i
numEQs = Len(lineOfText)
For i = 1 To numEQs
   separator = separator & "="
Next
 FunLine = VbCrLf & lineOfText & vbcrlf & separator
End Function

9.
Use the funLine function to create a header for the listing of each line that corresponds to a searched value. In this header, list how many matches were found. This header will go just before the For i = 0 To UBound(arrTxtArray) line of code in the Output section of your script. My header line looks like the following:

WScript.Echo funLine("There are " & ubound(arrTxtArray) &_
    " Lines with " & """" & Item & """" & " in them")

10.
Save and run the script. It should produce an output that looks similar to the following (abbreviated):

There are 58 Lines with "Error" in them
=======================================
07/16/2005 16:28:31.109,d:\xpsprtm\base\ntsetup\ ...

11.
If you look closely, you will notice that the script counts incorrectly. There are actually 59 lines in my log file that have the word "Error" in them. This is due to the array being zero based. To fix this, we need to add 1 to our count. This is seen below:

WScript.Echo funLine("There are " & ubound(arrTxtArray)+1 &_
   " Lines with " & """" & Item & """" & " in them")

12.
If your output does not look like this, or if you receive an error, compare your script to SearchTXTMultiValues.vbs.


Previous Page
Next Page