vb6 random number no duplicates & no zeros - random

I am using vb6 and trying to generate a random number or String with this format
S1 = "378125649"
I have three requirements NO Duplicates Values & No Zeros & 9 charcters in length
I have approached This two very different ways the random number generator method is failing the FindAndReplace works but is too much code
The questions are
How to fix the GetNumber method code to meet the three requirement?
OR
How to simplify the FindAndReplace code to reflect a completely new sequence of numbers each time?
GetNumber code Below
Private Sub GetNumber()
Randomize
Dim MyRandomNumber As Long 'The chosen number
Dim RandomMax As Long 'top end of range to pick from
Dim RandomMin As Long 'low end of range to pick from
'Dim Kount As Long 'loop to pick ten random numbers
RandomMin = 1
RandomMax = 999999999
MyRandomNumber = Int(Rnd(1) * RandomMax) + RandomMin
lbOne.AddItem CStr(MyRandomNumber) & vbNewLine
End Sub
The FindAndReplace Code Below
Private Sub FindAndReplace()
Dim S4 As String
S4 = "183657429"
Dim T1 As String
Dim T2 As String
Dim J As Integer
Dim H As Integer
J = InStr(1, S4, 2)
H = InStr(1, S4, 8)
T1 = Replace(S4, CStr(J), "X")
T1 = Replace(T1, CStr(H), "F")
If Mid(T1, 8, 1) = "F" And Mid(T1, 2, 1) = "X" Then
T2 = Replace(T1, "F", "8")
T2 = Replace(T2, "X", "2")
End If
tbOne.Text = CStr(J) & " " & CStr(H)
lbOne.AddItem "Original Value " & S4 & vbNewLine
lbOne.AddItem "New Value " & T2 & vbNewLine
End Sub

Here's a way of generating 9-digit random numbers with no zeroes. The basic idea is to build a 9-character string position by position where each position is a random number between 1 and 9. Then each string is added to a collection to remove any duplicates. This code will generate 100,000 unique numbers:
Option Explicit
Private Sub Command1_Click()
Dim c As Collection
Set c = GetNumbers()
MsgBox c.Count
End Sub
Private Function GetNumbers() As Collection
On Error Resume Next
Dim i As Integer
Dim n As String
Randomize
Set GetNumbers = New Collection
Do While GetNumbers.Count < 100000
n = ""
For i = 1 To 9
n = n & Int((9 * Rnd) + 1)
Next
GetNumbers.Add n, n
Loop
End Function
In my testing, this code only generated 2 duplicates for the 100,000 unique numbers returned.

I don't have a VB6 compiler, so I winged it:
Function GetNumber(lowerLimit as Integer, upperLimit As Integer) As Integer
Dim randomNumber As String
Dim numbers As New Collection
Randomize
For i As Integer = lowerLimit To upperLimit
Call numbers.Add(i)
Next
For j As Integer = upperLimit To lowerLimit Step -1
Dim position As Short = Int(((j - lowerLimit)* Rnd) + 1)
randomNumber = randomNumber & numbers(position)
Call numbers.Remove(position)
Next
Return(CInt(randomNumber))
End Function
Use that function by calling for example:
GetNumber(1, 9)

I don't have VB6 on my machines anymore, so here's a solution written in Excel that shuffles the digits in 123456789 using an array.
You should be able to use it with little conversion:
Private Function RndNumber() As String
Dim i, j As Integer
Dim tmp As Variant
Dim digits As Variant
digits = Array("1", "2", "3", "4", "5", "6", "7", "8", "9")
For i = 0 To UBound(digits)
j = Int(9 * Rnd)
tmp = digits(i)
digits(i) = digits(j)
digits(j) = tmp
Next
RndNumber = Join(digits, "")
End Function
Here's a variation to play with that will shuffle an array you pass in and join them together with the specified separator. Note that the arrays being passed in are of variant type so anything can be shuffled. The first array has numbers while the second array has strings:
Private Sub Foo()
Dim digits As Variant
digits = Array(1, 2, 3, 4, 5, 6, 7, 8, 9)
Dim rndNnumber As String
RndNumber = ShuffleArrayAndJoin(digits, "")
Debug.Print RndNumber
Dim pets As Variant
pets = Array("cat", "dog", "fish", "hamster")
Dim rndPets As String
rndPets = ShuffleArrayAndJoin(pets, ", ")
Debug.Print (rndPets)
End Sub
Private Function ShuffleArrayAndJoin(ByVal sourceArray As Variant, ByVal separator As String) As String
Dim i, j As Integer
Dim tmp As Variant
For i = 0 To UBound(sourceArray)
j = Int(UBound(sourceArray) * Rnd)
tmp = sourceArray(i)
sourceArray(i) = sourceArray(j)
sourceArray(j) = tmp
Next
ShuffleArrayAndJoin = Join(sourceArray, separator)
End Function

Function GetNumber() As String
Dim mNum As String
Randomize Timer
Do While Len(mNum) <> 9
mNum = Replace(Str(Round(Rnd(Timer), 6)) + Str(Round(Rnd(Timer), 3)), " .", "")
Loop
GetNumber = mNum
End Function
Been clicking a button to load a text box for a couple of minutes, but so far no dupes, and I'd bet money there never will be any..

Well, it solves just 1 problem: it will never ever repeat number
but it has to be 15+ numbers long...
Function genRndNr(nrPlaces) 'must be more then 10
Dim prefix As String
Dim suffix As String
Dim pon As Integer
prefix = Right("0000000000" + CStr(DateDiff("s", "2020-01-01", Now)), 10)
suffix = Space(nrPlaces - 10)
For pon = 1 To Len(suffix)
Randomize
Randomize Rnd * 1000000
Mid(suffix, pon, 1) = CStr(Int(Rnd * 10))
Next
genRndNr = prefix + suffix
End Function

Related

Change authKey of a user

Using SNMP version 3, I am creating a user.
Right now, I have it set up where I clone a user and that works just fine. However, I need to change the new user's authKey. How can I do this? I know the oid for authKeyChange, however, I don't know how to generate the new key. How do I generate that key? Can it be done using SNMPSharpNet?
If there is an easier way to do this while I'm creating the user, I can do that as well. ANY way to change the authKey (and privKey, but one step at a time) is much appreciated. I'm using VB.net if it means anything.
So I've figured out how to do this. It's a bit of a complex process. I followed this document, which is rfc2574. Do a ctrl+F for "keyChange ::=" and you'll find the paragraph walking you through the algorithm to generate the keyChange value. The following code has worked reliably to generate the keyChange value. All you have to do from this point is push the keyChange value to the usmAuthKeyChange OID. If you are changing the privacy password, you push the keyChange value to the usmPrivKeyChange OID. I'm ashamed to say that due to the time crunch, I did not have time to make this work completely, so when using SHA, I had to code an entirely new method that did almost the exact same thing. Again, I'm ashamed to post it, but I know how much I was banging my head against a wall, and if someone comes here later and sees this, I would like them to know what to do without going through the struggle.
Here is all of the code you need using VB.Net and the SNMPSharpNet library:
Private Function GenerateKeyChange(ByVal newPass As String, ByVal oldPass As String, ByRef target As UdpTarget, ByRef param As SecureAgentParameters) As Byte()
Dim authProto As AuthenticationDigests = param.Authentication
Dim hash As IAuthenticationDigest = Authentication.GetInstance(authProto)
Dim L As Integer = hash.DigestLength
Dim oldKey() As Byte = hash.PasswordToKey(Encoding.UTF8.GetBytes(oldPass), param.EngineId)
Dim newKey() As Byte = hash.PasswordToKey(Encoding.UTF8.GetBytes(newPass), param.EngineId)
Dim random() As Byte = Encoding.UTF8.GetBytes(GenerateRandomString(L))
Dim temp() As Byte = oldKey
Dim delta(L - 1) As Byte
Dim iterations As Integer = ((newKey.Length - 1) / L) - 1
Dim k As Integer = 0
If newKey.Length > L Then
For k = 0 To iterations
'Append random to temp
Dim merged1(temp.Length + random.Length - 1) As Byte
temp.CopyTo(merged1, 0)
random.CopyTo(merged1, random.Length)
'Store hash of temp in itself
temp = hash.ComputeHash(merged1, 0, merged1.Length)
'Generate the first 16 values of delta
For i = 0 To L - 1
delta(k * L + i) = temp(i) Xor newKey(k * L + i)
Next
Next
End If
'Append random to temp
Dim merged(temp.Length + random.Length - 1) As Byte
temp.CopyTo(merged, 0)
random.CopyTo(merged, temp.Length)
'Store hash of temp in itself
temp = hash.ComputeHash(merged, 0, merged.Length)
'Generate the first 16 values of delta
For i = 0 To (newKey.Length - iterations * L) - 1
delta(iterations * L + i) = temp(i) Xor newKey(iterations * L + i)
Next
Dim keyChange(delta.Length + random.Length - 1) As Byte
random.CopyTo(keyChange, 0)
delta.CopyTo(keyChange, random.Length)
Return keyChange
End Function
Private Function GenerateKeyChangeShaSpecial(ByVal newPass As String, ByVal oldPass As String, ByRef target As UdpTarget, ByRef param As SecureAgentParameters) As Byte()
Dim authProto As AuthenticationDigests = param.Authentication
Dim hash As IAuthenticationDigest = Authentication.GetInstance(authProto)
Dim L As Integer = 16
Dim oldKey() As Byte = hash.PasswordToKey(Encoding.UTF8.GetBytes(oldPass), param.EngineId)
Dim newKey() As Byte = hash.PasswordToKey(Encoding.UTF8.GetBytes(newPass), param.EngineId)
Array.Resize(oldKey, L)
Array.Resize(newKey, L)
Dim random() As Byte = Encoding.UTF8.GetBytes(GenerateRandomString(L))
Dim temp() As Byte = oldKey
Dim delta(L - 1) As Byte
Dim iterations As Integer = ((newKey.Length - 1) / L) - 1
Dim k As Integer = 0
If newKey.Length > L Then
For k = 0 To iterations
'Append random to temp
Dim merged1(temp.Length + random.Length - 1) As Byte
temp.CopyTo(merged1, 0)
random.CopyTo(merged1, random.Length)
'Store hash of temp in itself
temp = hash.ComputeHash(merged1, 0, merged1.Length)
Array.Resize(temp, L)
'Generate the first 16 values of delta
For i = 0 To L - 1
delta(k * L + i) = temp(i) Xor newKey(k * L + i)
Next
Next
End If
'Append random to temp
Dim merged(temp.Length + random.Length - 1) As Byte
temp.CopyTo(merged, 0)
random.CopyTo(merged, temp.Length)
'Store hash of temp in itself
temp = hash.ComputeHash(merged, 0, merged.Length)
Array.Resize(temp, L)
'Generate the first 16 values of delta
For i = 0 To (newKey.Length - iterations * L) - 1
delta(iterations * L + i) = temp(i) Xor newKey(iterations * L + i)
Next
Dim keyChange(delta.Length + random.Length - 1) As Byte
random.CopyTo(keyChange, 0)
delta.CopyTo(keyChange, random.Length)
Return keyChange
End Function
Private Function GenerateRandomString(ByVal length As Integer) As String
Dim s As String = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz"
Dim r As New Random
Dim sb As New StringBuilder
For i As Integer = 1 To length
Dim idx As Integer = r.Next(0, 51)
sb.Append(s.Substring(idx, 1))
Next
Return sb.ToString()
End Function
Again, I am oh so well aware this code is hideous, but it works, and that is all I needed in the meantime. I understand this is technical debt and not the way I should code, but it's here and I hope you can get some use out of it.
If this doesn't work, don't forget to go to frc2574 and look at the algorithm.

Quick sort in Visual Basic

I tried to make a quick-sort in VB2015, however when I run it, the values don't sort fully (however it does almost sort). I'm fairly sure that the problem has something to do with the two recurring lines.
Private Sub Button1_Click(sender As Object, e As EventArgs) Handles Button1.Click
numbers = TextBox1.Text.Split()
Dim tempstring As String
Form2.Show()
tempstring = ""
quicksort(numbers, numbers.Length() - 1, 0)
For Each a As String In numbers
tempstring = tempstring + a + " "
Next
TextBox2.Text = tempstring
Form2.Show()
Form2.Chart1.Series(0).Points.DataBindY(numbers)
End Sub
Public Sub quicksort(list As Array, high As Integer, low As Integer)
MessageBox.Show(Str(high) + " " + Str(low))
ListView1.Items.Add(Str(high) + " " + Str(low))
Dim i As Integer
Dim pivot As Integer
'pivot = (high + low) / 2
pivot = high
If high > low + 1 And low >= 0 Then
i = low
For c = low + 1 To high
If Int(list(c)) <= Int(list(pivot)) Then
swap(list, c, i)
i = i + 1
End If
Next
quicksort(numbers, i - 2, low)
quicksort(numbers, high, i)
End If
End Sub
Public Sub swap(list As Array, x As Integer, y As Integer)
Dim temp As Integer
temp = list(x)
list(x) = list(y)
list(y) = temp
Form2.Chart1.Series(0).Points.DataBindY(numbers)
'pause()
End Sub
I know this is old, but somebody may come across this. Your SWAP sub needs to pass the parameters ByRef, or the swap is only taking place inside the sub's variables and not within your QuickSort routine.

ASP Classic How to change the length of an array that is held by another array (not true 2d array)

I'm need to be able to have a 2d array, where the length of second array varies on a case by case basis. To this end, I made an array that contains other arrays with the following code:
Dim timeline
ReDim timeline(days)
for reDate = beginDate to endDate
timeline(DateDiff("d", beginDate, reDate)) = Array(0)
next
The problem I am having is that I am unable to change the size of any of the arrays contained by timeline, as ReDim doesn't seem to work when I do this. Does anyone know how I would go about this?
Try the below snippet, using a as temporary array variable:
Dim timeline, a
ReDim timeline(days)
' initial fill the array
For reDate = beginDate to endDate
a = Array()
ReDim a(99)
timeline(DateDiff("d", beginDate, reDate)) = a
Next
' redim sub arrays
For reDate = beginDate to endDate
' assign subarray to a
a = timeline(DateDiff("d", beginDate, reDate))
' redim a
ReDim Preserve a(199)
' put changed array into root array
timeline(DateDiff("d", beginDate, reDate)) = a
Next
In this case each subarray contains 100 elements first, and 200 after redim.
"Does not work" and error messages ("Object required") without code/context are not the best way to ask a question. The first is a complete waste of time; the second may indicate that you used Set where you shouldn't (VBScript Arrays are not objects, so there shouldn't be any Set in the code).
This demonstrates the same facts that #omegastripes pointed out, but gives hints wrt possible pitfalls:
Option Explicit
Dim AoA : AoA = Split("s o m e|w o r d s|o f|d i f f e r e n t|l e n g t h", "|")
Dim i
For i = 0 To UBound(AoA)
AoA(i) = Split(AoA(i))
Next
WScript.Echo "----- test data:"
For i = 0 To UBound(AoA)
WScript.Echo Join(AoA(i), "")
Next
WScript.Echo "----- array assignment copies (For Each elem ... does not 'work'):"
Dim e
For Each e In AoA
e = "zap"
Next
For Each e In AoA
WScript.Echo Join(e, "")
Next
WScript.Echo "----- array assignment copies (change needs index access):"
For i = 0 To UBound(AoA)
e = AoA(i)
e(0) = UCase(e(0)) ' just changes the copy (e)
WScript.Echo Join(e, "")
AoA(i)(1) = UCase(AoA(i)(1)) ' access via indices changes org collection
WScript.Echo Join(AoA(i), "")
Next
WScript.Echo "----- replace whole subarrays (re-dimensioned dynamically):"
Dim n, m
For i = 0 To UBound(AoA)
e = AoA(i)
n = UBound(e)
ReDim Preserve e(n * 2 + 1)
For m = n + 1 To UBound(e)
e(m) = UCase(e(m - n - 1))
Next
AoA(i) = e ' replace whole element
WScript.Echo Join(AoA(i), "")
Next
output:
cscript 37951664.vbs
----- test data:
some
words
of
different
length
----- array assignment copies (For Each elem ... does not 'work'):
some
words
of
different
length
----- array assignment copies:
Some
sOme
Words
wOrds
Of
oF
Different
dIfferent
Length
lEngth
----- replace whole subarrays:
sOmeSOME
wOrdsWORDS
oFOF
dIfferentDIFFERENT
lEngthLENGTH

How to convert a string string of key-value pairs into an array

I have below sample data. I want to convert this string into an array
device_name="Text Data" d_id=7454579598 status="Active" Key=947-4378-43248274
I tried below:
Const ForReading = 1
Set objFSO = CreateObject("Scripting.FileSystemObject")
Set objTextFile = objFSO.OpenTextFile _
("d:\vbfile.txt", ForReading)
Do Until objTextFile.AtEndOfStream
strNextLine = objTextFile.Readline
arrServiceList = Split(strNextLine , " ")
For i = 0 to Ubound(arrServiceList)
Wscript.Echo arrServiceList(i)
Next
Loop
it generates below
device_name="Text
Data"
d_id=7454579598
status="Active"
Key=947-4378-43248274
Expected output
device_name="Text Data"
d_id=7454579598
status="Active"
Key=947-4378-43248274
How about this approach:
Option Explicit
Const ForReading = 1
Dim FSO, keyValueExpr
Set FSO = CreateObject("Scripting.FileSystemObject")
Set keyValueExpr = New RegExp
keyValueExpr.Pattern = "\b(\w+)=(""[^""]*""|\S*)"
keyValueExpr.Global = True
Dim result, record, match
Set result = CreateObject("Scripting.Dictionary")
With FSO.OpenTextFile("D:\vbfile.txt", ForReading)
While Not .AtEndOfStream
Set record = CreateObject("Scripting.Dictionary")
result.Add result.Count + 1, record
For Each match In keyValueExpr.Execute(.ReadLine)
record.Add match.SubMatches(0), match.SubMatches(1)
Next
Wend
.Close
End With
Dim msg, lineNo, key
For Each lineNo In result
msg = "Line " & lineNo & vbNewLine
For Each key In result(lineNo)
msg = msg & vbNewLine & key & ": " & result(lineNo)(key)
Next
MsgBox msg
Next
It uses a regular expression that can identify key-value pairs that fulfill these conditions:
The key is a string of characters (a-z), digits (0-9) or underscores (_)
The value is anything that is either enclosed in double quotes or anything except a space.
Compare https://regex101.com/r/zL2mX5/1
The program creates nested dictionaries, the outer dictionary holding all lines of the file with the corresponding line numbers (1..n) for keys, each inner dictionary holds the key-value pairs found on each line.
This layout gives you the opportunity to address every value very conveniently:
value = result(3)("status")
Here is a function that might help. It takes a string and a delimiter and returns an array obtained by splitting on the delimiter -- whenever the delimiter isn't inside a quote:
Function SmartSplit(s, d)
Dim c, i, j, k, n, A, quoted
n = Len(s)
ReDim A(n - 1)
quoted = False
i = 1
k = 0
For j = 1 To n
c = Mid(s, j, 1)
If c = """" Then quoted = Not quoted
If c = d And Not quoted Then
A(k) = Mid(s, i, j - i)
k = k + 1
i = j + 1
End If
Next
If i < n Then
A(k) = Mid(s, i)
Else
k = k - 1
End If
ReDim Preserve A(k)
SmartSplit = A
End Function
In your example -- just replace Split by SmartSplit and it should work.

VBA - Remove both items from array when not unique

Quick question that I've been struggling with. I have 2 arrays of different lengths that contain strings.
I want to output a new array which removes BOTH the elements if a duplicate is detected. At the moment it only removes duplicates but leaves the original which is incorrect for what I am trying to accomplish.
E.g.
input = array ("cat","dog","mouse","cat")
expected output = array ("dog","mouse")
actual output = array ("cat","dog","mouse")
Code is below:
Sub removeDuplicates(CombinedArray)
Dim myCol As Collection
Dim idx As Long
Set myCol = New Collection
On Error Resume Next
For idx = LBound(CombinedArray) To UBound(CombinedArray)
myCol.Add 0, CStr(CombinedArray(idx))
If Err Then
CombinedArray(idx) = Empty
dups = dups + 1
Err.Clear
ElseIf dups Then
CombinedArray(idx - dups) = CombinedArray(idx)
CombinedArray(idx) = Empty
End If
Next
For idx = LBound(CombinedArray) To UBound(CombinedArray)
Debug.Print CombinedArray(idx)
Next
removeBlanks (CombinedArray)
End Sub
Thanks for all help and support in advance.
What about using Scripting.Dictionary? Like this:
Function RemoveDuplicates(ia() As Variant)
Dim c As Object
Set c = CreateObject("Scripting.Dictionary")
Dim v As Variant
For Each v In ia
If c.Exists(v) Then
c(v) = c(v) + 1
Else
c.Add v, 1
End If
Next
Dim out() As Variant
Dim nOut As Integer
nOut = 0
For Each v In ia
If c(v) = 1 Then
ReDim Preserve out(nOut) 'you will have to increment nOut first, if you have 1-based arrays
out(nOut) = v
nOut = nOut + 1
End If
Next
RemoveDuplicates = out
End Function
Here is a quick example. Let me know if you get any errors.
Sub Sample()
Dim inputAr(5) As String, outputAr() As String, temp As String
Dim n As Long, i As Long
inputAr(0) = "cat": inputAr(1) = "Hen": inputAr(2) = "mouse"
inputAr(3) = "cat": inputAr(4) = "dog": inputAr(5) = "Hen"
BubbleSort inputAr
For i = 1 To UBound(inputAr)
If inputAr(i) = inputAr(i - 1) Or inputAr(i) = temp Then
inputAr(i - 1) = "": temp = inputAr(i): inputAr(i) = ""
End If
Next i
n = 0
For i = 1 To UBound(inputAr)
If inputAr(i) <> "" Then
n = n + 1
ReDim Preserve outputAr(n)
outputAr(n) = inputAr(i)
End If
Next i
For i = 1 To UBound(outputAr)
Debug.Print outputAr(i)
Next i
End Sub
Sub BubbleSort(arr)
Dim value As Variant
Dim i As Long, a As Long, b As Long, c As Long
a = LBound(arr): b = UBound(arr)
Do
c = b - 1
b = 0
For i = a To c
value = arr(i)
If (value > arr(i + 1)) Xor False Then
arr(i) = arr(i + 1)
arr(i + 1) = value
b = i
End If
Next
Loop While b
End Sub
EDIT
Another way without sorting
Sub Sample()
Dim inputAr(5) As String, outputAr() As String
Dim n As Long, i As Long, j As Long
Dim RemOrg As Boolean
inputAr(0) = "cat": inputAr(1) = "Hen": inputAr(2) = "mouse"
inputAr(3) = "cat": inputAr(4) = "dog": inputAr(5) = "Hen"
For i = 0 To UBound(inputAr)
For j = 1 To UBound(inputAr)
If inputAr(i) = inputAr(j) Then
If i <> j Then
inputAr(j) = "": RemOrg = True
End If
End If
Next
If RemOrg = True Then
inputAr(i) = ""
RemOrg = False
End If
Next i
n = 0
For i = 0 To UBound(inputAr)
If inputAr(i) <> "" Then
n = n + 1
ReDim Preserve outputAr(n)
outputAr(n) = inputAr(i)
End If
Next i
For i = 1 To UBound(outputAr)
Debug.Print outputAr(i)
Next i
End Sub

Resources