I am trying to create a deciphering program which takes the entire English alphabet and shifts the letters' positioning to the left at one increment at a time. I have created a character array for this and I have got the shifting part to work. So, the index of each character in the array changes each time a shift is made. I also created an identical character array which does not shift so it has something to compare to.
Once the shift is made, I have textbox1 output into textbox2 which replaces the letters to their now corresponding letters based on the index of the first character array. For instance, "ABC" is now "DEF". The problem I am having is upon replacing the characters, it will replace them again because their state was changed previously. For example, I changed "A" to "B". Then I move on to changing "B" to "C". But since the "A" was changed to a "B", it is changed again to a "C". I realize doing a For Each Loop caused this to happen so I took it out of a loop and it still does it. I even tried putting a break in the code such as GOTO but that just stops the loop after changing the first letter.
Here is my code:
Private Sub cryptshift()
'SHIFTING ALL CHARACTERS IN ARRAY ONE SPACE TO THE LEFT
Dim temporaryStorageA As [String] = charArray(0)
Dim temporaryStorageB As [String]() = New [String](charArray.Length - 1) {}
For i As Integer = 1 To charArray.Length - 1
temporaryStorageB(i - 1) = charArray(i)
charArray(i - 1) = temporaryStorageB(i - 1)
Next
charArray(charArray.Length - 1) = temporaryStorageA
'CLEARING LABEL54 AND REALIGNING ARRAY TO LABEL53
Label54.Text = Nothing
For Each c In charArray
Label54.Text = Label54.Text & c & "-"
Next
'DECIPHERING
Dim mess As String = TextBox1.Text
Dim result As String = ""
For i As Integer = 0 To mess.Length - 1
Dim c As Char = mess(i)
Dim itemindex As Integer = Array.IndexOf(charArray2, c)
'**This IF Statement allows letters to be deciphered but also allows other characters such as punctuation, numbers and spaces to go through without any altering.**
If charArray2.Contains(c) Then
result &= charArray(itemindex)
Else
result &= c
End If
Next
TextBox2.Text = result
End Sub
Your problem is the .Replace. You should change only the current character. Here, I'm creating a new string with the result.
Dim mess As String = TextBox1.Text
Dim result As String = ""
For i As Integer = 0 To mess.length-1
Dim c As Char = mess(I)
Dim itemindex As Integer = Array.IndexOf(charArray2, c)
result &= charArray(itemindex)
Next
You could then use a string building.
Related
I'm currently creating a program that will take user input.
If the user input contains _, then a variable substring will then equal the first 4 characters (0,4) of that input.
From there, a loop is run that loops through an array, and within that loop is an If statement that determines if the array contains the substring. And if so, the position of the array element that contains the substring is then equal to the same position of a different element array. And if any element from that array doesn't contain the substring, a MsgBox displays saying error.
Currently, if the user inputs text that in fact is a substring of that input is contained within the array, it is still prompting the error message, as well as displaying the correct outcome. How would I correctly set this up to where if the substring is not found within the array, the MsgBox will prompt the error, and if it is, only the correct outcome will be executed. Here's what I currently have:
And yes I know that both arrays don't contain the same amount of elements, I'm just testing the first three values.
Dim i As Integer
Dim subString As String
Dim IdValues = New String() {"ADC_123", "AAA_123", "AAB_123", "EFGH_Company", "ABB_456", "ABC_456"}
Dim ValueValues = New String() {"Happy", "Sad", "Mad", "Excited", "Joyful"}
Dim charText As Char
charText = "_"
If txtDataEntry.Text.Contains(charText) Then ' if statement to determine if text contains a "_"
subString = txtDataEntry.Text.Substring(0, 4) 'sets variable subString to a substring of text data
For i = 0 To IdValues.Length - 1 'looping through array
If IdValues(i).Contains(subString) And txtDataEntry.Text.Contains(IdValues(i)) Then
MsgBox("Success, the position is at position " & i)
IdValues(i) = ValueValues(i) 'new array position now equals the IdValue array where the substring is found
lblValueResult.Text = IdValues(i) 'prints outcome to label
Else
MsgBox("Error")
End If
Next i
Else
MsgBox("Sorry, no value was found.")
End If
So if the user enters AAA_123 it will create a substring AAA_ and determine if the IdValues array contains that substring. It is prompting the correct execution, but it is also prompting the Error message. How should I correctly set this up.
Any help is appreciated!
Using a Boolean for these types of iteration process is always better than playing around with if else .Please try the below answer
Dim isValueFound As Boolean = False
Dim i As Integer
Dim subString As String
Dim IdValues = New String() {"ADC_123", "AAA_123", "AAB_123", "EFGH_Company", "ABB_456", "ABC_456"}
Dim ValueValues = New String() {"Happy", "Sad", "Mad", "Excited", "Joyful"}
Dim charText As Char
charText = "_"
If txtDataEntry.Text.Contains(charText) Then ' if statement to determine if text contains a "_"
subString = txtDataEntry.Text.Substring(0, 4) 'sets variable subString to a substring of text data
For i = 0 To IdValues.Length - 1 'looping through array
If IdValues(i).Contains(subString) And txtDataEntry.Text.Contains(IdValues(i)) Then
MsgBox("Success, the position is at position " & i)
IdValues(i) = ValueValues(i) 'new array position now equals the IdValue array where the substring is found
lblValueResult.Text = IdValues(i) 'prints outcome to label
isValueFound = True
Exit For
End If
Next i
If isValueFound = False Then
MsgBox("Error : Not Found")
End If
Else
MsgBox("Sorry, no value was found.")
End If
I have a column of data with unique strings where the first 4 characters in the string may be a repeat of the first 4 characters in another string, in a format similar to:
ABCDEF
ABCDXY
ABCDKL
DTYTZF
DTYTSD
I am attempting to loop through this data to identify which 4 starting characters appear more then three times. If the first 4 digits of the string occur 3 times or more, I would like to remove these from the array entirely, and end up with an array that excludes these values. For example, in my column above, as 3 strings or more begin with 'ABCD', I would like to remove all strings that begin with this code, and have only every other value remain, such that my result would be:
DTYTZF
DTYTSD
I am currently looping through the array, pushing any value that occurs three times or more into a NEW array, and plan to then use that list to do a second pass on the original array, and remove any matches. This may not be the most efficient way, but I've not been able to determine a better way that is guaranteed not to mess my data up.
I have worked through looping through the strings to identify which strings occur more then once, but when I try to push them to an array, the string successfully is pushed to the array, but is then replaced with the next value as soon as it is pushed to the array. I know the value is pushed correctly, because if I view the array immediately afterwards, I see the value in the array. When the next value is pushed and you view the array again, only the new value is displayed (The older ones are not).
I believe this is due to my limited understanding of ReDim-ing arrays, and me not fully understanding a code snippet for pushing this value into an array. My (condensed) code is as follows:
Sub pickupValues()
Dim valuesArray()
Dim i As Long
Dim y As Long
Dim sizeCheck As Long
Dim tempArray() As String
valuesArray() = Worksheets("Sheet1").Range("A1:A10").Value
For i = LBound(valuesArray) To UBound(valuesArray)
sizeCheck = 0
For y = LBound(valuesArray) To UBound(valuesArray)
If Left(valuesArray(i, 1), 4) = Left(valuesArray(y, 1), 4) Then
sizeCheck = sizeCheck + 1
i = y
If sizeCheck >= 3 Then
ReDim tempArray(1 To 1) As String 'I'm not sure why I need to do this.
tempArray(UBound(tempArray)) = Left(valuesArray(i, 1), 4) 'I believe this is what pushes the value into the array.
ReDim Preserve tempArray(1 To UBound(tempArray) + 1) As String 'Again unsure on what the purpose of this is.
viewArray (tempArray)
End If
End If
Next y
Next i
End Sub
Function viewArray(myArray)
Dim txt As String
Dim i As Long
For i = LBound(myArray) To UBound(myArray)
txt = txt + myArray(i) + vbCrLf
Next i
MsgBox txt
End Function
What am I doing wrong?
I would like to re-use the same basic code later in the function to push other values OUT of an array based on if they match the string or not, but it seems VBA does not like to move values out of arrays either. Is there an easy solution that would match both scenarios?
I've rewritten what you are trying to do. I'm using the filter function to quickly get your results in the array
Option Explicit
Public Sub pickupValues()
Dim tmp As Variant
Dim results As Variant
Dim i As Long
Dim v
' Make sure this matches your range
With ThisWorkbook.Sheets("Sheet1")
' Important to transpose the input here as Filter will only take a 1D array. Even though it's only 1 column, setting an array this way will generate a 2D array
tmp = Application.Transpose(.Range(.Cells(1, 1), .Cells(.Cells(.Rows.Count, 1).End(xlUp).Row, 1)).Value2)
End With
' ReDiming to the maximum value and slimming down afterwards is much quicker then increasing your array each time you've found a new value
ReDim results(1 To UBound(tmp))
For Each v In tmp
' Less then 2 as first result is '0'. Will return '-1' if can't be found but as test criteria is in the array it will always be at least 0
If UBound(Filter(tmp, Left(v, 4))) < 2 Then
i = i + 1
results(i) = v
End If
Next v
' Redim Preserve down to actual array size
If i > 0 Then
ReDim Preserve results(1 To i)
viewArray (results)
Else
MsgBox "Nothing Found"
End If
End Sub
' Should really be a sub as doesn't return anything back to caller
Public Sub viewArray(myArray)
MsgBox Join(myArray, vbCrLf)
End Sub
Your algorithm is not helping you.
Option 1:
Sort your array. Then you can make a single pass to find sequential values with the same first four characters and count them.
Option 2:
Use a Dictionary object: first four characters as key, number of occurrences as value.
Short disclaimer: This is my very first question, so please be understanding.
I'm trying to code a function in Excel VBA that takes a binary number (formatted as a string) that counts the spaces, the 0s, and outputs the consecutive amount of 0s (and adds one to it) until the next "1" in that string appears, with "," in between. At the very end of the string, if there's the a "1", the output should look like: "..., 1". I'll try to make a little easier to understand with an example:
Strings of length twelve:
101011010101 --> 2, 2, 1, 2, 2, 2, 1
110000101101 --> 1, 5, 2, 1, 2, 1
100010001000 --> 4, 4, 4
So far I've managed to make a one-dimensional boolean array that takes the string and splits it into parts of length 1, so to say a "binary array". But I couldn't test it, since I only have half of the function.
Function ABSTAND(str As String, size As Integer) As String
Dim i As Integer
Dim arrays(size) As Boolean
For i = 1 To Len(str)
If Mid(str, i, 1) = "1" Then
arrays(i) = True
Else
arrays(i) = False
End If
'Maybe all of this works in a loop?
'Count consecutive 0s, add one
'Output the value with ", " (Concatenate numbers with strings, or make the number a string)
'Count consecutive 0s again
'and so on...
'Add conditions for the last value: Don't add a ", " and check if a one is the last character
End Function
I know, it looks like I have already figured out the problem and only need to implement it, but I'm new to VBA and don't know that well how it works and how to fix syntax and other problems.
Also, I would like to have a generalized form of my problem, that works with every string length, if that's possible.
Unfortunately, VBA isn't the best language for dealing with arrays. I've written the function as described but it sounds like, from your description, you might want to remove the check for If Len(arrZeroes(i)) > 0 Then etc. because it looks like you want to return '1' values in those cases.
Have a play around with the 'Split' function to try get a better feel for it and how it relates to your problem.
Function ABSTAND(str As String) As String
Dim arrZeroes() As String
Dim arrResult() As String
Dim i As Integer
'Initialise arrResult dimensions
ReDim arrResult(1 To 1)
'Splits your binary number into an array with each element being zero or more 0's
'(if there are several 1's in a row or a 1 at the start or finish it returns 0-length element for that position)
arrZeroes = Split(str, "1")
'Loop through each element in this new array
For i = LBound(arrZeroes) To UBound(arrZeroes)
'Sets the top element of the result array to this length + 1 then increments the size (like appending to array)
arrResult(UBound(arrResult)) = Len(arrZeroes(i)) + 1
ReDim Preserve arrResult(1 To UBound(arrResult) + 1)
Next i
'The last step on the result array incremented its ubound which is still empty so we remove that
ReDim Preserve arrResult(1 To UBound(arrResult) - 1)
'then return the array joined!
ABSTAND = Join(arrResult, ", ")
End Function
Let me know if anything doesn't make sense!
Edit:
An array is basically like an indexed list of elements of a specified data type. The line Dim arrZeroes() as String is dimming a dynamic array of string elements. The benefit of using a dynamic array is that you can dynamically change the amount of elements in it using Redim. To get around the lack of an 'append' function, what you have to do is redim the array to make it one element bigger then set this new biggest element to your new value.
arrResult(UBound(arrResult)) = Len(arrZeroes(i)) + 1
ReDim Preserve arrResult(1 To UBound(arrResult) + 1)
That's what these lines are doing. What the Split function does is, given a string and a delimiter, cut the string into a load of slices at each occurrence of the delimiter and return the array. For example, Split("11101101", "0") returns {"111", "11", "1"}. Where there are more than one occurrence of the delimiter in sequence, or the delimiter appears at the beginning or end of the string, it outputs a zero-length element, such as Split("101101", "1") returns {, "0", , "0",}. What the function is doing is looking at the length of each of these slices (i.e. consecutive digits that are not the delimiter) and outputting them to a new array.
Remove the # in your code.
It is used for preprocessing directive, and you do not need it.
More about Preprocessing directives:
https://msdn.microsoft.com/VBA/Language-Reference-VBA/articles/ifthenelse-directive
In general, try the following code:
Option Explicit
Public Sub TestMe()
Debug.Print ABSTAND("101011010101", 12)
End Sub
Function ABSTAND(str As String, size As Long) As String
Dim i As Long
Dim arrays() As Variant
Dim strResult As String
ReDim arrays(size)
For i = 1 To Len(str)
If Mid(str, i, 1) = "1" Then
arrays(i) = True
Else
arrays(i) = False
End If
strResult = strResult & arrays(i)
Next i
ABSTAND = strResult
End Function
It would print something like TrueFalseTrueFalseTrueTrue... Then try to build up your solution further.
Just some points:
Pay attention how the Array is created.
Use Long instead of Integer.
You can shorten the ABSTAND function, to the following:
Function ABSTAND(str As String, size As Long) As String
Dim i As Long
Dim arrays() As Variant
Dim strResult As String
ReDim arrays(size)
For i = 1 To Len(str)
arrays(i) = Mid(str, i, 1) = "1"
strResult = strResult & arrays(i)
Next i
ABSTAND = strResult
End Function
I'm currently working on a program that will convert a string into "combined integer" (namely: from a string, it will be splitted into two characters at a time and then each character in each group will be converted into ASCII number. Then, the first character is multiplied by 256 (shift 8 bit to the left) and add second character. It must not eliminate/forget any character inside the string
Here is when the trouble really begin: it threw IndexOutOfRangeException
Dim input As String = TextBox1.Text.PadLeft(1)
Dim charArr As Char() = input.ToCharArray
Dim intGroup As UShort
Dim strout As String = ""
For index = 0 To charArr.Length - 2 Step 2
Dim i = index
Dim a = charArr(i)
Dim b = charArr(i + 1)
intGroup = CByte(AscW(a)) * 256 + CByte(AscW(b))
strout = strout + CStr(intGroup) + " "
Next
MsgBox(strout)
My guess was that I modify the index inside the loop which is 'forbidden'.
Any possible solution??
Thanks
I would do something like this but I don't know how you want to deal with odd length strings:
For index = 0 To charArr.Length - 1 Step 2
Dim a = charArr(index)
Dim b = If(index=charArr.Length - 1, _
<something to use for odd length strings>, _
charArr(index + 1))
intGroup = CByte(AscW(a)) * 256 + CByte(AscW(b))
strout = strout + CStr(intGroup) + " "
Next
I don't know what you want to use, especially if you bear in mind that .NET strings (unlike, say, C strings) can perfectly well contain a character with ascii code 0, so just using 0 may leave you with ambiguous data, depending on how you're using this string that you're constructing.
But basically, it comes down to you needing to do some special handling for odd length strings, and no magic manipulation of the for loop parameters will avoid that fact - you either deal with them in the loop (as above) or use a shorter loop (.Length - 2) and perform a length check afterwards and deal with the final character that you missed in the loop separately.
For index = 0 To input.Length - 2 step 2
array its zero based, so if the lenght = n, last element is arr[n-1].
for handle only odds element, the last element its arr[n-2].
I'm having trouble filling up empty array elements in a char array.
I have an inputArray that will store all the characters that I type for myInput into an array. I then created a charArray that will take the characters from inputArray and then if it it comes across nothing in the array I want to add -1 to signal empty locations in my charArray. I haven't been able to do that. I type "Hello", it will output back to me
H
E
L
L
O
Space
Space
Space
Space
And So On, until I reach the end of that array.
*"Space" is for visual aid of output
I'm lost. I want to be able to filter out the "-1" and than count for the number of underscores I need to make up the word, like "Hello" would be _ _ _ _ _ (leaving out elements with "-1" or nothing inside of it.)
Module GuessingGame
Sub Main()
Dim myInput As String.
Dim inputArray(11) As Char
Dim charArray(11) As Char
Dim myLetter As String
Dim attempts As Integer = 0
Dim incorrectAttempts As Integer = 0
Dim remainingAttempts As Integer = 0
myInput = InputBox$("Please enter a word or phrase: ")
inputArray = myInput.ToCharArray()
While inputArray.Length > 12
System.Console.WriteLine("Error: The word or phrase needs to be 12 characters or less")
myInput = InputBox$("Please enter a word or phrase: ")
inputArray = myInput.ToCharArray()
End While
For i = 0 to inputArray.length - 1
If IsNothing(inputArray(i)) Then
charArray(i) = "-1"
Else
charArray(i) = inputArray(i)
End If
Next
Console.Clear()
For Each element In charArray
System.Console.WriteLine(element)
Next element
For i = 0 to inputArray.length - 1
remainingAttempts = remainingAttempts + 1
Next
remainingAttempts = remainingAttempts - 1
System.Console.WriteLine("Guessing Game Display")
System.Console.WriteLine("---------------------")
System.Console.WriteLine("Number of Remaining Attempts: " & remainingAttempts)
System.Console.WriteLine("Number of Incorrect Attempts: " & incorrectAttempts)
System.Console.WriteLine("Number of Attempts: " & attempts)
System.Console.WriteLine("Guess a Character? ")
myLetter = InputBox$("Please enter a character: ")
End Sub
End Module
I am not 100% but I am pretty sure the IsNothing is checking to see if there is a value at all.. Since you are automatically assigning the array to a size of 11 anything after the H E L L O is going to be set, but either "" or " " just an empty space. So try doing this
If inputArray(i) == "" Then
charArray(i) = "-1"
Else
charArray(i) = inputArray(i)
End If
I think your code work fine it must print -1 when there is space in integerArray. But on the code below u must modify it:
While inputArray.Length > 12
System.Console.WriteLine("Error: The word or phrase needs to be 12 characters or less")
myInput = InputBox$("Please enter a word or phrase: ")
'**/*it is better to remove these two code and replace it by goto above*/**
inputArray = myInput.ToCharArray()
End While
I was able to achieve what I wanted by first creating the char array, which would have the input of the word to guess. Then make string arrays, one that had the values from the char array and one that I would use for the guess array to compare off the first string array.
This was the work around to this problem.