Remove duplicate values from a string in classic asp - vbscript

I have below code in classic asp
str=Request.Form("txt_str")
"txt_str" is text box in a classic asp form page where I am entering below values:
000-00001
000-00001
000-00001
000-00002
response.write str
hence str will be 000-00001 000-00001 000-00001 000-00002
array = split(str,Chr(44))
if str <> "" then
x=empty
for i = 0 to ubound(array)
if array(i) <> "" then
array_2 = split(array(i),chr(13) & chr(10))
for j = 0 to ubound(array_2)
if array_2(j) <> "" then
if x=empty then
x= "'" & array_2(j) & "'"
else
x= x & ",'" & array_2(j) & "'"
end if
end if
next
end if
next
End if
response.write x
hence x will be returned as '000-00001','000-00001','000-00001','000-00002'
I want to remove duplicate values from x and display only it as:
x = '000-00001','000-00002'
How can i achieve this.Any help on this would be appreciated.
Thanks

To remove duplicates of string lists, the best option IMO is to use a Dictionary object. You can use this short function to do the task on a given string array:
Function getUniqueItems(arrItems)
Dim objDict, strItem
Set objDict = Server.CreateObject("Scripting.Dictionary")
For Each strItem in arrItems
objDict.Item(strItem) = 1
Next
getUniqueItems = objDict.Keys
End Function
A simple test:
' -- test output
Dim arrItems, strItem
arrItems = Array("a","b","b","c","c","c","d","e","e","e")
For Each strItem in getUniqueItems(arrItems)
Response.Write "<p>" & strItem & "</p>"
Next
This is a sample for your use case:
' -- sample for your use case
Dim strInput, x
strInput = Request.Form("txt_str")
x = "'" & join(getUniqueItems(split(str, Chr(44))), "','") & "'"
BTW, did you notice that Array and Str are VBScript Keywords, so you may run into issues with using such variable names. Therefore, I think it is common practice in VBScript to use prefixes for variable names.

If it's a ordered list, consider using a variable with last value:
lastval = ""
array = split(str,Chr(44))
if str <> "" then
x=empty
for i = 0 to ubound(array)
if array(i) <> "" then
array_2 = split(array(i),chr(13) & chr(10))
for j = 0 to ubound(array_2)
if array_2(j) <> "" then
if array_2(j) <> lastval then
lastval = array_2(j)
if x=empty then
x= "'" & array_2(j) & "'"
else
x= x & ",'" & array_2(j) & "'"
end if
end if
end if
next
end if
next
End if

Related

Calculation in 1 line VBS

How can I make this Calculator work if the user enters 1+1?
It only works if I enter 1 + 1 ;C
The calculation must be in 1 line.
x = inputbox("Calculation", "Calculator", "1+1")
y = Split(x)
if not isnumeric (y(0)) then
wscript.quit
end if
if not isnumeric (y(2)) then
wscript.quit
end if
if y(1) = "+" then
z = int(y(0)) + int(y(2))
msgbox(z)
end if
if y(1) = "-" then
z = int(y(0)) - int(y(2))
msgbox(z)
end if
if y(1) = "*" then
z = int(y(0)) * int(y(2))
msgbox(z)
end if
if y(1) = "/" then
z = int(y(0)) / int(y(2))
msgbox(z)
end if
if y(1) = "%" then
z = int(y(0)) MOD int(y(2))
msgbox(z)
end if
Thanks for any Answer!
Try next code snippet (commented for explanation):
Dim ii, sOperator, strExpr, y
strExpr = inputbox("Calculation", "Calculator", "1+1")
' insert spaces around all operators
For Each sOperator in Array("+","-","*","/","%")
strExpr = Trim( Replace( strExpr, sOperator, Space(1) & sOperator & Space(1)))
Next
' replace all multi spaces with a single space
Do While Instr( strExpr, Space(2))
strExpr = Trim( Replace( strExpr, Space(2), Space(1)))
Loop
y = Split(strExpr)
''' your script continues here
Another approach (allows more than pure arithmetic operations) using Eval Function (which evaluates an expression and returns the result) and basic error handling:
option explicit
On Error GoTo 0
Dim strResult: strResult = Wscript.ScriptName
Dim strExpr, strInExp, strLastY, yyy
strInExp = "1+1"
strLastY = ""
Do While True
strExpr = inputbox("Last calculation:" & vbCR & strLastY, "Calculator", strInExp)
If Len( strExpr) = 0 Then Exit Do
''' in my locale, decimal separator is a comma but VBScript arithmetics premises a dot
strExpr = Replace( strExpr, ",", ".") ''' locale specific
On Error Resume Next ' enable error handling
yyy = Eval( strExpr)
If Err.Number = 0 Then
strInExp = CStr( yyy)
strLastY = strExpr & vbTab & strInExp
strResult = strResult & vbNewLine & strLastY
Else
strLastY = strExpr & vbTab & "!!! 0x" & Hex(Err.Number) & " " & Err.Description
strInExp = strExpr
strResult = strResult & vbNewLine & strLastY
End If
On Error GoTo 0 ' disable error handling
Loop
Wscript.Echo strResult
Wscript.Quit
Sample output:
==> cscript //NOLOGO D:\VB_scripts\SO\39934370.vbs
39934370.vbs
1+1 2
2/4 0,5
0.5**8 !!! 0x3EA Syntax error
0.5*8 4
4=4 True
True+5 4
4=5 False
False+5 5
5 5
==>
I have found a much simpler way if having multiple files doesnt matter where you log it to a .txt file and use "set /a" in batch to simple calculate it.
In the vbs file:
calculation = inputbox("What do you want to calculate?(include =)", "Eclips-Terminal Calculator")
oFile.write "" & calculation & ""
oFile.close
wsh.run "calculator.bat"
wscript.sleep 3000
msgbox rfile.readall
oFile.close
In the batch file(calculator.bat):
#echo off
set /p math=<RAM.txt
set /a calculation=%math%
echo. >> RAM.txt
echo %calculation% >> RAM.txt
And then a text file called "RAM.txt".
Its my nice, clean and simple way wich isnt too hard to pull of.
EDIT: I know this is a 4 year old question i just couldnt find a simple fix so i added it here so others can find it.

Delete empty rows in CSV files in vbscript

I'm trying to export CSV files and this is my code.
The Excel CSV files have some empty cells and I wanted to delete them so I added some code (which I have marked in the comments).
The program doesn't have any errors but the empty cell still there.
Hopefully, someone can tell me what's wrong.
<%Option Explicit%>
<%
Dim strConn, strScriptName,strSQL
strConn = Application("eDSNSMS")
strSQL = Request.querystring("SQL")
sub Write_CSV_From_Recordset(RS)
if RS.EOF then
exit sub
end if
dim RX
set RX = new RegExp
RX.Pattern = "\r|\n|,|"""
dim i
dim Field
dim Separator
do until RS.EOF
Separator = ""
for i = 0 to RS.Fields.Count - 1
Field = RS.Fields(i).Value & ""
if RX.Test(Field) then
Field = """" & Replace(Field, """", """""") & """"
end if
If Left(Field, 2) = "01" and InStr(Field, "-") <> 0 Then
if Len(Field) = 11 Then
Field = "6" & Field
Field = """" & Replace(Field, "-", "") & """"
else
Field = ""
end if
elseif Left(Field, 2) = "01" and InStr(Field, "-") = 0 then
if Len(Field) = 10 Then
Field = "6" & Field
else
Field = ""
end if
elseif Left(Field, 3) = "011" and InStr(Field, "-") <> 0 then
if Len(Field) = 12 Then
Field = "6" & Field
Field = """" & Replace(Field, "-", "") & """"
else
Field = ""
end if
elseif Left(Field, 3) = "011" and InStr(Field, "-") = 0 then
if Len(Field) = 11 Then
Field = "6" & Field
else
Field = ""
end if
elseif Left(Field, 2) <> "01" and IsNumeric(Field) = true then
Field = ""
elseif Left(Field, 2) <> "01" and InStr(Field, "-") <> 0 then
Field = ""
end if
Response.Write Separator & Field
Separator = ","
next
Response.Write vbNewLine
RS.MoveNext
loop
end sub
Dim objRS, objConn, objFile, objFSO, strNewContents
' Const ForReading = 1
' Const ForWriting = 2
set objConn = server.CreateObject("ADODB.Connection")
objConn.ConnectionString = strConn
objConn.Open
set objRS = server.CreateObject("ADODB.RecordSet")
objRS.Open strSQL, strConn, 0, 1
' Set objFSO = CreateObject("Scripting.FileSystemObject")
' Set objFile = objFSO.OpenTextFile("export.csv", ForReading)
' Do Until objFile.AtEndOfStream
' strLine = objFile.Readline
' strLine = Trim(strLine)
' If Len(strLine) > 0 Then
' strNewContents = strNewContents & strLine & vbCrLf
' End If
' Loop
' objFile.Close
' Set objFile = objFSO.OpenTextFile("export.csv", ForWriting,true)
' objFile.Write strNewContents
' objFile.Close
Write_CSV_From_Recordset objRS
Response.ContentType = "text/csv"
Response.AddHeader "Content-Disposition", "attachment;filename=export.csv"
%>
If you want to keep from writing empty fields to your CSV, test the field just before you write it. For example, change:
Response.Write Separator & Field
To:
If Len(Field) > 0 Then
Response.Write Separator & Field
End If
But unless all values in this specific column/field are blank, doing this is going to throw off the alignment of your CSV.

HTA with dynamically generated HTML Tables with onclick faults

Right. I need help here. I have a HTA, and it runs completely fine. UNTIL I do the following to my code. I am working with VBScript. Code below:
<Script language="vbscript">
Sub DisplayDB_Click
Dim conn, str1, str2
str2 = "Hello"
MainTitle.InnerHTML = "<h2>Main Call Queue</h2>"
Set conn = CreateObject("ADODB.Connection")
conn.Open "DSN=LongbowLogin"
Set rsData = conn.Execute("SELECT * FROM MainTable WHERE CallStat='Open' ORDER BY P_ID DESC;")
str1 = "<table border=1 cellpadding=5><tr><th>Call Id</th><th>Full Name</th><th>Postcode</th><th>Site Code</th><th>Problem Title</th><th>Category</th><th>SubCategory</th><th>Call Status</th></tr>"
Do Until rsData.EOF = True
str1 = str1 & "<tr><td onclick=msgbox(str2)>" & rsData("P_Id") & "</td><td>" & rsData("FirstN") & "</td><td>" & rsData("PostCode") & "</td><td>" & rsData("SiteNumber") & "</td><td>" & rsData("PTitle") & "</td><td>" & rsData("PCat") & "</td><td>" & rsData("SCat") & "</td><td>" & rsData("CallStat") & "</td></tr>"
rsData.moveNext
Loop
str1 = str1 & "</table>"
MainDisplay.InnerHTML = str1
conn.Close
Call CheckState
End Sub
This code makes a HTML Table out of a SQL Select Statement and places it in a Span tag named MainDisplay under InnerHTML. This part works beautifully. However - After I add the
< td onclick='msgbox(str2)' > part, it will not work.
I click the first cell, and I get a message: "Line 1, 'str2' is not defined.".
I actually want it to say
< td onClick='CellID Me') > , CellID being a sub later in the same script block. I am doing this msgbox to troubleshoot.
str2 clearly is defined, so I'm clearly missing something here...
Any help here would be great, I'm going mad...
Many Thanks.
VBScript does no variable interpolation:
>> Dim str2 : str2 = "I'm str2 and this is my content"
>> Dim sRes : sRes = "<td onclick=MsgBox str2></td>"
>> WScript.Echo sRes
>>
<td onclick=MsgBox str2></td>
You'll have to splice the content into the result - and follow VBScript's rules about parentheses and quotes:
>> Dim str2 : str2 = "I'm str2 and this is my content"
>> Dim sRes : sRes = "<td onclick='MsgBox """ & str2 & """'></td>"
>> WScript.Echo sRes
>>
<td onclick='MsgBox "I'm str2 and this is my content"'></td>
This explains your immediate problem. Your real world task - attach a onclick event handler to all TDs - is better solved by creating the table using the DOM (.createElement, appendChild) than by trying to tame string concatenations into .innerHTML.
To make the MsgBox work you'll have to change this:
"<tr><td onclick=msgbox(str2)>" & rsData("P_Id") & ...
into this:
"<tr><td onclick='msgbox(""" & str2 & """)'>" & rsData("P_Id") & ...
However, I already told you that the code
"<tr><td onclick='Cell Me'>" & rsData("P_Id") & ...
works in principle. I verified this with an HTA that creates a table from a CSV on button-click.
VBScript:
Sub DisplayDB_Click
Set conn = CreateObject("ADODB.Connection")
conn.Open "Driver={Microsoft Text Driver (*.txt; *.csv)};" & _
& "Dbq=c:\Temp;Extensions=asc,csv,tab,txt;"
Set rsData = conn.Execute("SELECT * FROM sample.csv;")
str1 = "<table border=1 cellpadding=5><tr>"
For Each field In rsData.Fields
str1 = str1 & "<th>" & field.Name & "</th>"
Next
str1 = str1 & "</tr>"
Do Until rsData.EOF
str1 = str1 & "<tr>"
For Each field In rsData.Fields
str1 = str1 & "<td onclick='Cell Me'>" & field.Value & "</td>"
Next
str1 = str1 & "<tr>"
rsData.moveNext
Loop
str1 = str1 & "</table>"
MainDisplay.InnerHTML = str1
conn.Close
End Sub
Sub Cell(obj)
MsgBox obj.innerHtml
End Sub
HTML:
<p><input type="button" onClick="DisplayDB_Click" value="Show Table"/></p>
<div id="MainDisplay"></div>
If this code doesn't work for you, the issue is somewhere else in the HTA.
As Ekkehard.Horner suggested, the table could also be created using createElement and appendChild, e.g. like this:
Sub Cell
MsgBox Me.innerHtml
End Sub
Function NewField(text, isHeader)
If isHeader Then
Set e = document.createElement("th")
Else
Set e = document.createElement("td")
End If
e.AppendChild document.createTextNode(text)
e.onClick = GetRef("Cell")
Set NewField = e
End Function
Function NewRow(values, isHeader)
Set r = document.createElement("tr")
For Each v In values
r.appendChild NewField(v, isHeader)
Next
Set NewRow = r
End Function
Sub DisplayDB_Click
...
lastCol = rsData.Fields.Count-1
Dim cols
ReDim cols(lastCol)
For i = 0 To lastCol
cols(i) = rsData.Fields(i).Name
Next
Set thead = document.createElement("thead")
thead.appendChild NewRow(cols, True)
Set tbody = document.createElement("tbody")
Do Until rsData.EOF
For i = 0 To LastCol
cols(i) = rsData.Fields(i).Value
Next
tbody.appendChild NewRow(cols, False)
rsData.MoveNext
Loop
Set table = document.createElement("table")
table.appendChild thead
table.appendChild tbody
document.getElementById("parent").appendChild table
...
End Sub

How to enter values in cells in Excel in a column with VBscript

Set objReadFile = objFSO.OpenTextFile(objFile.Path, ForReading)
strAll = Split(objReadFile.ReadAll, vbCrLf, -1, vbTextCompare) 'Gets each line from file
i = LBound(strAll)
Do While i < UBound(strAll)
If (InStr(1, strAll(i), "DAU SNo.-C0", vbTextCompare) > 0) Then
i = i + 4 'Skip 4 lines to get to first SN
Do Until InStr(1, strAll(i), "+", vbTextCompare) > 0 'Loop until line includes "+"
strSNO = Split(strAll(i), "|", -1, vbTextCompare)
'put strSNO into next cell in column A
**objSheet.Cells.Offset(1,0).Value = Trim(strSNO(1))**
i = i + 1
Loop
End If
i = i + 1
Loop
This code splits a text file successfully and puts the two values I want in strSNO(1) and strSNO(2). I want to write them into column A row 2 and column B row 2, then put the next value in row 3 in the next iteration of the loop. I tried the offset method and it gave errors. All the help I am finding is for VBA. Can anyone tell me what to put where the code is in bold to fix it?
EDIT:
Solved it.This is what I did:
strAll = Split(objReadFile.ReadAll, vbCrLf, -1, vbTextCompare) 'Gets each line from file
i = LBound(strAll)
c=2
Do While i < UBound(strAll)
If (InStr(1, strAll(i), "DAU SNo.-C0", vbTextCompare) > 0) Then
i = i + 4 'Skip 4 lines to get to first SN
Do Until InStr(1, strAll(i), "+", vbTextCompare) > 0 'Loop until line includes "+"
strSNO = Split(strAll(i), "|", -1, vbTextCompare)
i = i + 1
objSheet.Cells(c,1).Offset(1,0).Value = Trim(strSNO(1))
objSheet.Cells(c,2).Offset(1,0).Value = Trim(strSNO(2))
c=c+1
Loop
End If
i = i + 1
Loop
Replace
objSheet.Cells.Offset(1,0).Value = Trim(strSNO(1))
with
objSheet.Cells(i,1).Value = Trim(strSNO(1))
objSheet.Cells(i,2).Value = Trim(strSNO(2))
Edit: Are you certain you want the fields 1 and 2 of strSNO? VBScript arrays are 0-based, so the first index is 0, not 1.
To locate an error add some debugging code:
On Error Resume Next
objSheet.Cells(i,1).Value = Trim(strSNO(1))
If Err Then
WScript.Echo i & ": " & strAll(i)
WScript.Echo "strSNO(1) = " & strSNO(1)
WScript.Echo "strSNO(1) is of type " & TypeName(strSNO(1))
End If
Err.Clear
objSheet.Cells(i,2).Value = Trim(strSNO(2))
If Err Then
WScript.Echo i & ": " & strAll(i)
WScript.Echo "strSNO(2) = " & strSNO(2)
WScript.Echo "strSNO(2) is of type " & TypeName(strSNO(2))
End If
On Error Goto 0
If the problem turns out to be that strAll(i) doesn't contain a | for some i, so the Split() produces an array with just one element, you can work around that by something like this:
strSNO = Split(strAll(i) & "|", "|", -1, vbTextCompare)

Passing objects as arguments in VBScript

I'm working on a project to capture various disk performance metrics using VBScript and would like to use a sub procedure with an object as an argument. In the following code samples the object I'm referring to is objitem.AvgDiskQueueLength which will provide a value for the disk queue length. I haven't found a way to make it work since it is recognized as a string and then doesn't capture the value. My goal is to make it easy for anyone to change the counters that are to be captured by only having to make a change in one location(the procedure call argument). The way I'm going about this may not be the best but I'm open to suggestions. The sub procedure call is below.
PerfCounter "Average Disk Queue Length", "disk_queueLength", "objItem.AvgDiskQueueLength"
The following code is the sub procedure.
Sub PerfCounter(CounterDescription, CounterLabel, CounterObject)
Set colItems = objWMIService.ExecQuery("SELECT * FROM Win32_PerfFormattedData_PerfDisk_PhysicalDisk",,48)
args_index = args_index + 1
arrCriteria = split(command_line_args(args_index),",")
strDriveLetter = UCase(arrCriteria(0))
intCriticalThreshold = arrCriteria(1)
intWarningThreshold = arrCriteria(2)
For Each objItem in colItems
With objItem
WScript.Echo "objitem.name = " & objitem.name
If InStr(objItem.Name, strDriveLetter & ":") > 0 Then
intChrLocation = InStr(objItem.Name, strDriveletter)
strInstanceName = Mid(objItem.Name, intChrLocation, 1)
End If
If strDriveLetter = strInstanceName AND InStr(objItem.Name, strDriveLetter & ":") > 0 Then
If intActiveNode = 1 OR Len(intActiveNode) < 1 Then
WScript.Echo "CounterDescription = " & CounterDescription
WScript.Echo "CounterLabel = " & CounterLabel
WScript.Echo "CounterObject = " & CounterObject
If CInt(CounterOjbect) => CInt(intCriticalThreshold) Then
arrStatus(i) = "CRITICAL: " & strDriveLetter & ": " & CounterDescription
arrTrendData(i) = CounterLabel & "=" & CounterObject
intExitCode = 2
arrExitCode(i) = intExitCode
ElseIf CInt(CounterOjbect) => CInt(intWarningThreshold) AND CInt(CounterObject) < CInt(intCriticalThreshold) Then
arrStatus(i) = "WARNING: " & strDriveLetter & ": " & CounterDescription
arrTrendData(i) = CounterLabel & "=" & CounterObject
intExitCode = 1
arrExitCode(i) = intExitCode
Else
arrStatus(i) = "OK: " & strDriveLetter & ": " & CounterDescription
arrTrendData(i) = CounterLabel & "=" & CounterObject
intExitCode = 0
arrExitCode(i) = intExitCode
End If
Else
PassiveNode CounterDescription, CounterLabel
End If
End If
End With
Next
i = i + 1
ReDim Preserve arrStatus(i)
ReDim Preserve arrTrendData(i)
ReDim Preserve arrExitCode(i)
End Sub
Why cant you do this...
PerfCounter "Average Disk Queue Length", "disk_queueLength", objItem.AvgDiskQueueLength
To pass an object you have to pass an object, not a string. To make this method work as expected you would have to have the object prior to the procedure call, but in your code example it looks like you are trying to pass an object that you don't have. A working example:
Set objFSO = CreateObject("Scripting.FileSystemObject")
UseFileSystemObject objFSO
Sub UseFileSystemObject( objfso)
'Now I can use the FileSystemObject in this procedure.
End Sub
But calling the UseFileSystemObject procedure like this will not work,
UseFileSystemObject "objFSO"
because you are passing in a string not an object.
The only way I can think of to accomplish what you want is to use a select statement to write the appropriate attribute of the object, something like this.
Call PerfCounter "Average Disk Queue Length", "disk_queueLength", "AvgDiskQueueLength"
Sub PerfCounter(CounterDescription, CounterLabel, CounterObjectAttribute)
Set colItems = objWMIService.ExecQuery("SELECT * FROM Win32_PerfFormattedData_PerfDisk_PhysicalDisk",,48)
For Each objItem in colItems
Select Case CounterObjectAttribute
Case "ObjectAttribute1"
Case "ObjectAttribute2"
Case "AvgDiskQueueLength"
Wscript.Echo objItem.AvgDiskQueueLength
End Select
Next
End Sub
So in the select you would have to add a case for each attribute that can be used, but it would allow you to pass a string into the procedure. I might be way off on this, but I don't know how you can pass an object if you don't have the object first.

Resources