Solved

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

Posted on 2004-08-21
6
303 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
Comment Utility
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
Comment Utility
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
Comment Utility
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
Find Ransomware Secrets With All-Source Analysis

Ransomware has become a major concern for organizations; its prevalence has grown due to past successes achieved by threat actors. While each ransomware variant is different, we’ve seen some common tactics and trends used among the authors of the malware.

 

Author Comment

by:gscotte
Comment Utility
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
Comment Utility
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
Comment Utility
Your code seems to work perfectly.That was FAST!
0

Featured Post

Why You Should Analyze Threat Actor TTPs

After years of analyzing threat actor behavior, it’s become clear that at any given time there are specific tactics, techniques, and procedures (TTPs) that are particularly prevalent. By analyzing and understanding these TTPs, you can dramatically enhance your security program.

Join & Write a Comment

Suggested Solutions

Title # Comments Views Activity
Batch file output 20 76
wordsFront challenge 8 64
noX challenge 17 75
Problem to open Excel file 15 34
There is an easy way, in .NET, to centralize the treatment of all unexpected errors. First of all, instead of launching the application directly in a Form, you need first to write a Sub called Main, in a module. Then, set the Startup Object to th…
This article will show, step by step, how to integrate R code into a R Sweave document
This video teaches viewers about errors in exception handling.
The viewer will learn how to user default arguments when defining functions. This method of defining functions will be contrasted with the non-default-argument of defining functions.

728 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

Need Help in Real-Time?

Connect with top rated Experts

11 Experts available now in Live!

Get 1:1 Help Now