VBScript to combine rs values, loop and add to duplicate(s) - vbscript

I've written a lot of IF statements in VBScript, but haven't gone much beyond that so apologize for my lack of experience. I hope what I'm asking is simple to do.
I want to output item identifiers created by three combined recordset field values and add "B" "C" "D" etc., to any duplicates. Duplicates are rare, but do happen occasionally. I want to do this for meaningful item identification which autonumbers do not provide.
The following example works to combine fields, but then I need to include script to loop and find the duplicates and add the appropriate alpha character.
FYI: a = alpha character, b = alpha character, c = reformatted date
<% Dim idCode
a = (rs_table.Fields.Item("CodeA").Value)
b = (rs_table.Fields.Item("CodeB").Value)
c = (fixedDate(rs_table.Fields.Item("Date").Value))
idCode = (a) & (b) & (c)
Response.write idCode
%>
example output: LC032414
example dupe output: LC032414B
Thanks, I'm almost afraid to ask and may find this more pain than what it's worth!

I would probably use a Dictionary to store the ID's, since you can add each as a key (which must be unique) and test the Dictionary for its existence. Something like this:
' Early on... create a dictionary...
Set d = CreateObject("Scripting.Dictionary")
' Loop through your records...
Do Until rs_table.EOF
' Determine your ID...
idCode = rs_table("CodeA") & rs_table("CodeB") & fixedDate(rs_table("Date"))
' Check for existence in the dictionary...
If d.Exists(idCode) Then
' ID already exists. Keep testing suffixes until we find an availability...
strLetter = "B"
Do While d.Exists(idCode & strLetter)
strLetter = Chr(Asc(strLetter) + 1)
Loop
d.Add idCode & strLetter, "" ' Add the ID/key. The value is unimportant.
Else
' This ID doesn't exist yet. Just add it.
d.Add idCode, "" ' Add the ID/key. The value is unimportant.
End If
rs_table.MoveNext
Loop
When it comes time to print your ID's, you can just iterate the dictionary's Keys collection:
For Each k In d.Keys
Response.Write k
Next

Related

reading between two values

I have to read between 2 values after asking the users if he want between the '' or not between.
Exemple if the user select 1 in the text
'Hi' My name is 'Kev'in and i'm happ'y' to be 'there'
he will have
'Hi' 'Kev' 'y' 'there'
in a text file. If he chose 2, he will have
My name is in and i'm happ to be
Right now I'm using
Do While objScriptFile.AtEndOfStream <> True
strCurrentLine = objScriptFile.ReadLine
intIsComment = InStr(1,strCurrentLine,"'")
If intIsComment > 0 Then
objCommentFile.Write strCurrentLine & vbCrLf
End If
Loop
Else
For now it's only reading both of the value (between '' and not between) but I have no idea how to change it.
That's pretty simple, provided the delimiter is unique. Split the line at ' and output either the even or the odd array elements, depending on whether 1 or 2 was chosen.
...
strCurrentLine = "'Hi' My name is 'Kev'in and i`m happ'y' to be 'there'"
arr = Split(strCurrentLine, "'")
For i = choice To UBound(arr) Step 2
objCommentFile.Write arr(i)
Next
...
The value of choice is your users' selection (either 1 or 2).
Note that for this to work the strings must not contain apostrophes anywhere else. As #Ekkehard.Horner pointed out in his comment you can't use the delimiter character elsewhere in the text (i'm), because otherwise it would be impossible to distinguish where it was intended to be a delimiter and where not.

How to remove duplicate from an array using vb script without using dictionary objects?

I am trying to remove duplicates from array using for loop and conditional statement.But I am unable to create new array without any duplicates.There is xls having country name with duplicates,i am aiming to remove duplicates and create a new array with unique country names.
For e.g
strFilePath="D:\Country.xls"
Set objExcel = CreateObject("Excel.Application")
objExcel.Visible=True
Set objWorkbook = objExcel.Workbooks.Open (strFilePath)
Set objSheet=objExcel.Sheets("Country")
objExcel.DisplayAlerts = False
objExcel.AskToUpdateLinks = False
objExcel.AlertBeforeOverwriting = False
Dim A(100)
Dim B(100)
For i = 2 To 6 Step 1
k = i-2
A(k)=objSheet.Cells(i,1).Value
Next
B(0)=A(0)
For j = 0 To 4 Step 1
strIt=A(j)
For m = 1 To 4 Step 1
reslt = StrComp(A(m),strIt,1)
If(reslt = 1 Or reslt = -1) Then
c=1
B(c)=A(m)
c=c+1
End if
m=m+1
Next
Next
Two options, depending on your needs:
Try using a hash table of the country names. When entering values in to the hash table you could do a simultaneous check to see whether you encounter an identical value. If it finds one it will abort entering the new value and continue with the next one, otherwise it will be entered in to the table. At the end of it you will have your list of unique country names.
Sort the list of countries and then do a second pass that removes duplicate countries (since duplicates will now be grouped together)
Problems with both of these methods is that they dont preserve original order unless you keep some sort of "original index" value and then sort based on that value once you remove duplicates.
Here's how I usually do it:
Dim uniqueentries()
ReDim uniqueentries(-1)
' Here you could go through your existing array and
' call "GetUniqueEntries" sub on each entry, e.g.
For Each i In oldarray
GetUniqueEntries i
Next
Sub GetUniqueEntries(newentry)
Dim entry
If UBound(uniqueentries) >= 0 Then ' Only check if uniqieentries contains any entries
For Each entry In uniqueentries
If newentry = entry Then Exit Sub ' If the entry you're testing already exists in array then exit sub
Next
End If
ReDim Preserve uniqueentries(UBound(uniqueentries) + 1) ' Increase new array size
uniqueentries(UBound(uniqueentries)) = newentry ' Add unique entry to new array
End Sub
This could be done more simpler way by using Split command. Please check the below solution, if any clarification let me know.
Dim aDupl
Dim aNew, strNew
aDupl = Array("A", "B", "A", "D", "C", "D")
strNew = ""
For iCnt= 0 To UBound(aDupl)
If InStr(strNew,aDupl(iCnt) ) = 0 Then
strNew =strNew&aDupl(iCnt)&","
End If
Next
aNew = Split(strNew, ",")
For iCnt=0 To UBound(aNew)
WScript.Echo aNew(iCnt)
Next

Is there a way to make special characters work when using InStr in VBScript?

A VBScript is in use to shorten the system path by replacing entries with the 8.3 versions since it gets cluttered with how much software is installed on our builds. I'm currently adding the ability to remove duplicates, but it's not working correctly.
Here is the relevant portion of code:
original = "apple;orange;apple;lemon\banana;lemon\banana"
shortArray=Split(original, ";")
shortened = shortArray(1) & ";"
For n=2 to Ubound(shortArray)
'If the shortArray element is not in in the shortened string, add it
If NOT (InStr(1, shortened, shortArray(n), 1)) THEN
shortened = shortened & ";" & shortArray(n)
ELSE
'If it already exists in the string, ignore the element
shortened=shortened
End If
Next
(Normally "original" is the system path, I'm just using fruit names to test...)
The output should be something like
apple;orange;lemon\banana
The issue is entries with punctuation, such as lemon\banana, seem to be skipped(?). I've tested it with other punctuation marks, still skips over it. Which is an issue, seeing how the system path has punctuation in every entry.
I know the basic structure works, since there are only one of each entry without punctuation. However, the real output is something like
apple;orange;lemon\banana;lemon\banana
I thought maybe it was just a character escape issue. But no. It still will not do anything with entries containing punctuation.
Is there something I am doing wrong, or is this just a "feature" of VBScript?
Thanks in advance.
This code:
original = "apple;orange;apple;lemon\banana;lemon\banana"
shortArray = Split(original, ";")
shortened = shortArray(0) ' array indices start with 0; & ";" not here
For n=1 to Ubound(shortArray)
'If the shortArray element is not in in the shortened string, add it
'i.e. If InStr() returns *number* 0; Not applied to a number will negate bitwise
' If 0 = InStr(1, shortened, shortArray(n), 1) THEN
If Not CBool(InStr(1, shortened, shortArray(n), 1)) THEN ' if you insist on Not
WScript.Echo "A", shortArray(n), shortened, InStr(1, shortened, shortArray(n), vbTextCompare)
shortened = shortened & ";" & shortArray(n)
End If
Next
WScript.Echo 0, original
WScript.Echo 1, shortened
WScript.Echo 2, Join(unique(shortArray), ";")
Function unique(a)
Dim d : Set d = CreateObject("Scripting.Dictionary")
Dim e
For Each e In a
d(e) = Empty
Next
unique = d.Keys()
End Function
output:
0 apple;orange;apple;lemon\banana;lemon\banana
1 apple;orange;lemon\banana
2 apple;orange;lemon\banana
demonstrates/explains your errors (indices, Not) and shows how to use the proper tool for uniqueness (dictionary).

Copy most recent file from a batch of alike files using vbscript

I am not sure if this is possible or not. I am not even sure where to begin. I have a couple thousand files where the file names are named as so:
nnnnnnnnnnnnnnnn.yyyyddmm.pdf (n = number, yyyy = year, dd = day, and mm = month).
Within these thousands of files, there are batches of alike files that have the same nnnnnnnnnnnnnnnnnn part of the filename but the .yyyyddmm is different in order to represent the date of the file. (These batches of alike files will be merged together at a later point but that is not important to this scenario).
My question is, Is there a way to compare the yyyyddmm part of the alike files and have the most recent date files get copied to a different folder? I need the file that has the most recent date of the alike files on the filename get copied to a different folder.
The reason that I am having issues with this is because I am not sure if it is possible to compare parts of the filename to see which one is in fact the file that has the most recent date. I know that there is a way that this can be done through looking at the date modified date but this will not always give me the alike file with the most recent date.
Any thoughts?? Please let me know if I could provide more information.
Trying to understand your problem/specs. Assume a loop over the files of your .pdf folder results in:
Looking at "0000000000012345.20120402.pdf"
Looking at "0000000000012345.20120502.pdf"
Looking at "0000000000012348.20121702.pdf"
Looking at "0000000000012346.20120802.pdf"
Looking at "0000000000012347.20121002.pdf"
Looking at "0000000000012348.20121602.pdf"
Looking at "0000000000012347.20121302.pdf"
Looking at "0000000000012347.20121202.pdf"
Looking at "0000000000012345.20120202.pdf"
Looking at "0000000000012348.20121502.pdf"
Looking at "0000000000012346.20120602.pdf"
Looking at "0000000000012346.20120902.pdf"
Looking at "0000000000012348.20121402.pdf"
Looking at "0000000000012346.20120702.pdf"
Looking at "0000000000012347.20121102.pdf"
Looking at "0000000000012345.20120302.pdf"
Would
Last file for 0000000000012345 is 0000000000012345.20120502.pdf
Last file for 0000000000012348 is 0000000000012348.20121702.pdf
Last file for 0000000000012346 is 0000000000012346.20120902.pdf
Last file for 0000000000012347 is 0000000000012347.20121302.pdf
identify the files to copy correctly? If yes, say so and I will post the code here.
First, you need a class to obtain and store the info put into the file names:
' cut & store info about file(names) like "0000000000012347.20121202.pdf"
Class cCut
Private m_sN ' complete file name
Private m_sG ' group/number prefix part
Private m_dtF ' date part; converted to ease comparisons
Public Function cut(reCut, sFiNa)
Set cut = Me ' return self/this from function
Dim oMTS : Set oMTS = reCut.Execute(sFiNa)
If 1 = oMTS.Count Then
m_sN = sFiNa
Dim oSM : Set oSM = oMTS(0).SubMatches
m_sG = oSM(0)
m_dtF = DateSerial(oSM(1), oSM(3), oSM(2))
Else
' Err.Raise
End If
End Function ' cut
Public Property Get G() : G = m_sG : End Property ' G
Public Property Get D() : D = m_dtF : End Property ' D
Public Property Get N() : N = m_sN : End Property ' N
End Class ' cCut
Then just loop over the .Files and check the date parts for each group stored in a dictionary (number prefix part used as key):
' The one and only .pdf folder - no recursion into subfolders!
Dim sTDir : sTDir = "..\data\test"
' dictionary to store the last/most recently used file for each group
Dim dicG : Set dicG = CreateObject("Scripting.Dictionary")
' RegExp to cut/parse file names like "0000000000012345.20120402.pdf"
Dim reCut : Set reCut = New RegExp
reCut.Pattern = "^(\d{16})\.(\d{4})(\d{2})(\d{2})\.pdf$"
Dim oFile
For Each oFile In goFS.GetFolder(sTDir).Files
WScript.Echo "Looking at", qq(oFile.Name)
' an oCut object for each file name
Dim oCut : Set oCut = New cCut.cut(reCut, oFile.Name)
If Not dicG.Exists(oCut.G) Then
' new group, first file, assume this is the latest
Set dicG(oCut.G) = oCut
Else
' found a better one for this group?
If dicG(oCut.G).D < oCut.D Then Set dicG(oCut.G) = oCut
End If
Next
WScript.Echo "-----------------------"
Dim sG
For Each sG In dicG.Keys
WScript.Echo "Last file for", sG, "is", dicG(sG).N
Next
WRT comments:
All my (ad hoc/proof of concept) scripts start with
Option Explicit
Dim goFS : Set goFS = CreateObject( "Scripting.FileSystemObject" )
and contain some functions dealing with different aspects/stragegies for a solution to a common problem/topic. When I post code here, I copy/paste working/tested code out of the middle of a function frame like
' ============================================================================
goXPLLib.Add _
"useDic02", "use a dictionary (Mark II)"
' ----------------------------------------------------------------------------
' ============================================================================
Function useDic02()
useDic02 = 1 ' assume error
' The one and only .pdf folder - no recursion into subfolders!
...
Next
useDic02 = 0 ' success
End Function ' useDic02
(yes, there is a first attempt function "useDic()" that was guilty of storing all the oCuts for each group to be processed in a second loop; yes, there is a function "createTestData()" I needed to set up/fill my TDir). Sometimes I'm sloppy and forget about goFS, please accept my apologies.
The variable names are part of an experiment. I used to advocate type-prefixed long variable names upto and including
Dim nIdx
For nIdx = 0 To UBound(aNames)
aNames(nIdx) = ...
Next
Other people argued that nIdx-alikes variables just add some letters to mistype but no additional meaning over i, and that aNames-alikes can't be understood without the context and if you have that, aN would be a just as good remainder for "The first names of the kings of persia from the currently processed file to be compared to the names in the database".
So I thought: Given that there are 3 interesting aspects of a file name (full name to copy, number prefix to group, date part to compare/decide) and that there is half a screen between
Private m_sN ' complete file name
and
Public Property Get N() : N = m_sN : End Property ' N
and given that you need just those 3 properties of the Cut object to use it in
Dim oCut : Set oCut = New cCut.cut(reCut, oFile.Name)
If Not dicG.Exists(oCut.G) Then
' new group, first file, assume this is the latest
Set dicG(oCut.G) = oCut
Else
' found a better one for this group?
If dicG(oCut.G).D < oCut.D Then Set dicG(oCut.G) = oCut
will the average short time memory cope with oCut.D?
Obviously not.
To copy the selected files:
Assuming you want the files copied to an existing folder "..\data\latest", use
goFS.CopyFile goFS.BuildPath(sTDir, dicG(sG).N), "..\data\latest\", True
instead of/in addition to the line
WScript.Echo "Last file for", sG, "is", dicG(sG).N
I did not anticipate that .CopyFile chokes on relative source pathes; so consider replacing the *N*ame property of the cCut class with a *P*ath property.
Trying to use
dicG(sG).Copy "..\data\latest\", True
results in:
Microsoft VBScript runtime error: Object doesn't support this property or method: 'dicG(...).Copy'
because the objects stored aren't files (which have a .Copy method), but cCuts (which don't).
How I would handle it:
I would make a dictionary with for each unique number part a separate key. The value will be an array with all file names sharing that key (and thus sharing the unique number part)
For each key in the dictionary, I will loop through the items in the array, searching for the most recent date.
Approach:
Get a file
Extract number part
See if a key for that number part exist. If not create a key for that number with an empty array as value
Add the filename as a new item to the array
Loop to 1. until all files are handled
Get a key
Get the first file in the attached array. Remember the date and the arrayindex
Get the next file, if the date is higher than the remembered date, update the date to this date and the arrayindex to this array index
Loop to 8. until the end of the array is reached
Store the file with the arrayindex as the most recent file for that unique number
loop to 6. until all keys are handled

vbscript - Replace all spaces

I have 6400+ records which I am looping through. For each of these: I check that the address is valid by testing it against something similar to what the Post Office uses (find address). I need to double check that the postcode I have pulled back matches.
The only problem is that the postcode may have been inputted in a number of different formats for example:
OP6 6YH
OP66YH
OP6 6YH.
If Replace(strPostcode," ","") = Replace(xmlAddress.selectSingleNode("//postcode").text," ","") Then
I want to remove all spaces from the string. If I do the Replace above, it removes the space for the first example but leave one for the third.
I know that I can remove these using a loop statement, but believe this will make the script run really slow as it will have to loop through 6400+ records to remove the spaces.
Is there another way?
I didn't realise you had to add -1 to remove all spaces
Replace(strPostcode," ","",1,-1)
Personally I've just done a loop like this:
Dim sLast
Do
sLast = strPostcode
strPostcode = Replace(strPostcode, " ", "")
If sLast = strPostcode Then Exit Do
Loop
However you may want to use a regular expression replace instead:
Dim re : Set re = New RegExp
re.Global = True
re.Pattern = " +" ' Match one or more spaces
WScript.Echo re.Replace("OP6 6YH.", "")
WScript.Echo re.Replace("OP6 6YH.", "")
WScript.Echo re.Replace("O P 6 6 Y H.", "")
Set re = Nothing
The output of the latter is:
D:\Development>cscript replace.vbs
OP66YH.
OP66YH.
OP66YH.
D:\Development>
This is the syntax Replace(expression, find, replacewith[, start[, count[, compare]]])
it will default to -1 for count and 1 for start. May be some dll is corrupt changing the defaults of Replace function.
String.Join("", YourString.Split({" "}, StringSplitOptions.RemoveEmptyEntries))
Because you get all strings without spaces and you join them with separator "".

Resources