Solved

Perl or VBS script to sort delimited text file which has dependencies

Posted on 2004-08-21
6
305 Views
Last Modified: 2008-02-01
I need a Perl or VBScript script that can sort a comma delimeted text file based on multiple dependencies. Each line of the file has at least one string. Some lines have additional comma delimited strings. The initial sort should be alphabetic based on the first string. The additional strings are dependencies. The second sort should consider the dependencies and should shift the lines up or down to meet the dependencies. I have been unable to develop a script to solve the dependency problem.

In the case: "stringC,stringD,stringA" stringC is dependent first on string D then on stringA.

#Unsorted
stringB,stringD
stringG,stringD
stringD,stringA
StringH,stringB
stringE,stringG
stringF,StringE,stringA,stringB
stringC,stringD,stringA
stringA

#Sorted
stringA
stringD,stringA
stringB,stringD
stringC,stringD,stringA
stringG,stringD
stringE,stringG
stringF,StringE,stringA,stringB
StringH,stringB

If anyone can point me toward an existing Perl or VBScript that can be easily modified to do the job, that would be great.
0
Comment
Question by:gscotte
  • 3
  • 3
6 Comments
 
LVL 20

Expert Comment

by:dsacker
ID: 11862337
Do you mind putting a * by each sort key. I don't understand your sort logic.

For example, if as you say "stringC,stringD,stringA" stringC is dependent first on string D then on stringA, then I would have thought "stringD" was the primary sort key. And it appears to be in the correct sort order if that is the case.

Not so with your last record in the "#Sorted" list. If "StringH,stringB" means that StringH is dependent on stringB, then wouldn't stringB by the primary sort key and not be last?

Also, I notice you have the word "string" sometimes start with a capital "S", sometimes not. Is this intentional? If so, are they to be sorted as case sensitive?
0
 

Author Comment

by:gscotte
ID: 11863987
Thanks for your reply. The upper/lower case "S" in "string" was unintentional. If you can ignore case that would be best.  I'll try to explain my sorting requirements again. Think of it as a list of software to be installed on a system; some things have pre-requisites before they can be installed. First you'd get a list of software and sort it alphabetically simply for readability. Next you see that some things have pre-requisites that require you to reshuffle the order a bit to meet the pre-requisites. In the case you mentioned above, "StringH,stringB", StringH required stringB. However, StringH was in it's proper alphabetical position and didn't need to be moved up because stringB did precede it. In other words both of it's requirements were met. In the case of the line "stringC,stringD,stringA" I had to break alphabetical order to get stringD ahead of stringC because stringC required stringD. Does that make sense?
0
 
LVL 20

Expert Comment

by:dsacker
ID: 11865292
I think so (lol). Let me reword it, and as a result, if someone else beats me to the code solution, just remember who laid out the technical specs for them (lol).

Starting from the RIGHT to the LEFT on any given record, if the string item has already been listed, select the next string item to the LEFT of it, until you find one that has NOT been listed. That then becomes the next appropriate key.

I would also assume that any record that has only one item (i.e. stringA) becomes a primary record for sorting. In other words, if there had been a record that only had stringC, that would have been third in the sorted list. Am I correct?

If these are correct assumptions, I'll begin working on some code for you.
0
How Do You Stack Up Against Your Peers?

With today’s modern enterprise so dependent on digital infrastructures, the impact of major incidents has increased dramatically. Grab the report now to gain insight into how your organization ranks against your peers and learn best-in-class strategies to resolve incidents.

 

Author Comment

by:gscotte
ID: 11865904
I think a solution based on your assumptions would work perfectly for my needs. Thanks for your thoughtful approach.
0
 
LVL 20

Accepted Solution

by:
dsacker earned 500 total points
ID: 11870888
I've written a VBScript for this. Invoke it in your command prompt window using the following command:

cscript //nologo vbscript.vbs inputfile.txt

Obviously replace vbscript.vbs with whatever you choose to name the code, and replace inputfile.txt with your input file.

When you're ready to output it to a file, just add the following to the command:

cscript //nologo vbscript.vbs inputfile.txt > outputfile.txt

Here is the code:

Dim margFile
Dim mblnDebg
Dim mblnDisplayed
Dim mintCnt
Dim mintMax
Dim mobjArg
Dim mobjFileSystem
Dim mobjTextFile
Dim mobjWShell
Dim mstrRecord
dim mstrList()
Dim mstrSortList()

Call Get_Arguments

Set mobjFileSystem = CreateObject("Scripting.FileSystemObject")
set mobjTextFile = mobjFileSystem.OpenTextFile(margFile,1,2)

mintCnt = 0
Do While mobjTextFile.AtEndOfStream = False
   mstrRecord = mobjTextFile.ReadLine
   mintCnt = mintCnt + 1
   ReDim Preserve mstrList(mintCnt)
   ReDim Preserve mstrSortList(mintCnt)
   mstrList(mintCnt) = mstrRecord
   mstrSortList(mintCnt) = LCase(mstrRecord)
Loop
mintMax = mintCnt

mobjTextFile.Close

Set mobjTextFile = Nothing
Set mobjFileSystem = Nothing

Call Sort_Driver(mintMax)
Call Display_Sorted_Records

Sub Get_Arguments
'-----------------------------------------------'
'      Expecting two arguments:            '
'          1.      File name                  '
'          2.      Debug option                  '
'-----------------------------------------------'
    margFile = ""
    mblnDisplayed = False
    For Each mobjArg in WScript.Arguments
        If lcase(left(trim(mobjArg),3)) = "deb" then
           mblnDebg = True
        Else
           If margFile = "" Then
              margFile = mobjArg
           End If
        End If
    Next
End Sub

Sub Display_Sorted_Records
    Dim ndx
    Dim strRecord

    For ndx = 1 to mintMax
        strRecord = Return_Record(mstrSortList(ndx))
        WScript.Echo strRecord
    Next
End Sub

Sub Sort_Driver(maxItems)
    Dim ndx1
    Dim ndx2
    Dim intItem
    Dim strItem
    Dim strRecord
    Dim strUsedItems

    Call Sort_Items(maxItems, 1)
    strUsedItems = "|" & mstrSortList(1) & "|"

    For ndx1 = 2 to (maxItems - 1)
        For ndx2 = ndx1 to maxItems
            If Prerequisites_Installed(mstrSortList(ndx2), strUsedItems) Then
               strRecord = mstrSortList(ndx1)
               mstrSortList(ndx1) = mstrSortList(ndx2)
               mstrSortList(ndx2) = strRecord
               Call Sort_Items(maxItems, (ndx1 + 1))
               Exit For
            End If
        Next
        intItem = How_Many_Items(mstrSortList(ndx1))
        strItem = Return_Item(mstrSortList(ndx1), intItem)
        strUsedItems = strUsedItems & strItem & "|"
    Next
End Sub

Sub Sort_Items(maxItems, intStart)
    Dim ndx1
    Dim ndx2
    Dim cnt
    Dim strItem
    Dim strRecord

    For ndx1 = intStart to (maxItems - 1)
        For ndx2 = (ndx1 + 1) to maxItems
            If mstrSortList(ndx2) < mstrSortList(ndx1) Then
               strRecord = mstrSortList(ndx1)
               mstrSortList(ndx1) = mstrSortList(ndx2)
               mstrSortList(ndx2) = strRecord
            End If
        Next
    Next
End Sub

Function Prerequisites_Installed(strRecord, strUsedItems)
    Dim ndx
    Dim intItems
    Dim strItem

    intItems = How_Many_Items(strRecord)
    For ndx = 1 to (intItems - 1)
        strItem = Return_Item(strRecord, ndx)
        If InStr(strUsedItems, "|" & strItem & "|") = 0 Then
           Prerequisites_Installed = False
           Exit Function
        End If
    Next

    Prerequisites_Installed = True
End Function

Function How_Many_Items(strRecord)
    Dim count
    Dim ndx
    Dim length

    length = Len(strRecord)
    If length = 0 Then
       Exit Function
    End If

    count = 0

    For ndx = 1 to length
        If Mid(strRecord, ndx, 1) = "," Then
           count = count + 1
        End If
    Next

    If Right(strRecord, 1) <> "," Then
       count = count + 1
    End If

    How_Many_Items = count
End Function

Function Return_Item(strRecord, intItem)
    Dim count
    Dim ndx
    Dim length
    Dim strChar
    Dim strItem

    If InStr(strRecord, ",") = 0 Then
       If intItem = 1 Then
          Return_Item = strRecord
       End If
       Exit Function
    End If

    count = 0
    length = Len(strRecord)
    strItem = ""

    For ndx = length to 1 step -1
        strChar = Mid(strRecord, ndx, 1)
        If strChar = "," Then
           count = count + 1
        End If
        If count = intItem Then
           Exit For
        End If
        If strChar = "," Then
           strChar = ""
           strItem = ""
        End If
        strItem = strChar & strItem
    Next
    Return_Item = strItem
End Function

Function Return_Record(strRecord)
    Dim ndx

    For ndx = 1 to mintMax
        If LCase(mstrList(ndx)) = LCase(strRecord) Then
           Return_Record = mstrList(ndx)
           Exit For
        End If
    Next
End Function
0
 

Author Comment

by:gscotte
ID: 11877090
Your code seems to work perfectly.That was FAST!
0

Featured Post

Networking for the Cloud Era

Join Microsoft and Riverbed for a discussion and demonstration of enhancements to SteelConnect:
-One-click orchestration and cloud connectivity in Azure environments
-Tight integration of SD-WAN and WAN optimization capabilities
-Scalability and resiliency equal to a data center

Question has a verified solution.

If you are experiencing a similar issue, please ask a related question

Suggested Solutions

The following is a collection of cases for strange behaviour when using advanced techniques in DOS batch files. You should have some basic experience in batch "programming", as I'm assuming some knowledge and not further explain the basics. For some…
When we want to run, execute or repeat a statement multiple times, a loop is necessary. This article covers the two types of loops in Python: the while loop and the for loop.
The goal of the video will be to teach the user the concept of local variables and scope. An example of a locally defined variable will be given as well as an explanation of what scope is in C++. The local variable and concept of scope will be relat…
The viewer will learn additional member functions of the vector class. Specifically, the capacity and swap member functions will be introduced.

808 members asked questions and received personalized solutions in the past 7 days.

Join the community of 500,000 technology professionals and ask your questions.

Join & Ask a Question