Reversing Digits - vb.net

I'm trying to make a function that takes a three digit number and reverses it (543 into 345)
I can't take that value from a TextBox because I need it to use the three numbers trick to find a value.
RVal = ReverseDigits(Val)
Diff = Val - RVal
RDiff = ReverseDigits(Diff)
OVal = Diff + RDiff
543-345=198
198+891=1089
Then it puts 1089 in a TextBox
Function ReverseDigits(ByVal Value As Integer) As Integer
' Take input as abc
' Output is (c * 100 + b * 10 + a) = cba
Dim ReturnValue As Boolean = True
Dim Val As String = CStr(InputTextBox.Text)
Dim a As Char = Val(0)
Dim b As Char = Val(1)
Dim c As Char = Val(2)
Value = (c * 100) + (b * 10) + (a)
Return ReturnValue
End Function
I've tried this but can't figure out why it won't work.

You can convert the integer to a string, reverse the string, then convert back to an integer. You may want to enforce the three digit requirement. You can validate the argument before attempting conversion
Public Function ReverseDigits(value As Integer) As Integer
If Not (value > 99 AndAlso value < 1000) Then Throw New ArgumentException("value")
Return Integer.Parse(New String(value.ToString().Reverse().ToArray()))
End Function
My code is pretty simple and will also work for numbers that don't have three digits assuming you remove that validation. To see what's wrong with your code, there are a couple of things. See the commented lines which I changed. The main issue is using Val as a variable name, then trying to index the string like Val(0). Val is a built in function to vb.net and the compiler may interpret Val(0) as a function instead of indexing a string.
Function ReverseDigits(ByVal Value As Integer) As Integer
' Dim ReturnValue As Boolean = True
' Dim Val As String = CStr(InputTextBox.Text)
Dim s As String = CStr(Value)
Dim a As Char = s(0)
Dim b As Char = s(1)
Dim c As Char = s(2)
Value = Val(c) * 100 + Val(b) * 10 + Val(a)
'Return ReturnValue
Return Value
End Function
(Or the reduced version of your function, but I would still not hard-code the indices because it's limiting your function from expanding to more or less than 3 digits)
Public Function ReverseDigits(Value As Integer) As Integer
Dim s = CStr(Value)
Return 100 * Val(s(2)) + 10 * Val(s(1)) + Val(s(0))
End Function
And you could call the function like this
Dim inputString = InputTextBox.Text
Dim inputNumber = Integer.Parse(inputString)
Dim reversedNumber = ReverseDigits(inputNumber)
Bonus: If you really want to use use math to find the reversed number, here is a version which works for any number of digits
Public Function ReverseDigits(value As Integer) As Integer
Dim s = CStr(value)
Dim result As Integer
For i = 0 To Len(s) - 1
result += CInt(Val(s(i)) * (10 ^ i))
Next
Return result
End Function

Here's a method I wrote recently when someone else posted basically the same question elsewhere, probably doing the same homework:
Private Function ReverseNumber(input As Integer) As Integer
Dim output = 0
Do Until input = 0
output = output * 10 + input Mod 10
input = input \ 10
Loop
Return output
End Function
That will work on a number of any length.

Related

Generate unique serial number incrementally

I am writing a vb.net program to generate a three digit serial number I will use in printing a barcode.
The requirements are the counter must count:
001 - 999, A00 - A99, B00 - B99, ..., Z00 - Z99
I cannot use the letters O and I
This code simply increments the value I pass to it by 1. I first check if the value is <=998 and if so return the value in 3 digits. I had to put this in a Try statement because passing the value 'A00' caused an error.
The code is still breaking once I hit Z99.
Problem: If the next serial number = Z90 and the user wants to print 35 barcodes I need to stop the operation before it begins and warn the user there are only 10 avail serial numbers remaining
Also, I am also hoping for advice on how I could have accomplished this in a better manner, any advice would be greatly appreciated
Public Shared Function NextSerial(ByVal value As String) As String
Try
If value <= 998 Then
value += 1
Return ZeroPad(value, 3)
End If
Catch ex As Exception
End Try
Const chars As String = "ABCDEFGHJKLMNPQRSTUVWXYZ"
Dim threenumber As String = ZeroPad(value, 3) 'ensure value is 3 digits.
Dim alpha As String = threenumber.Substring(0, 1).ToUpper() ' 1st digit
Dim beta As String = threenumber.Substring(1, 2) 'remaining two digits
Dim newNumber As String
Dim nextletter As String
If beta = "99" Then
beta = "00"
nextletter = chars.Substring((chars.IndexOf(alpha, System.StringComparison.Ordinal) + 1), 1)
newNumber = nextletter + beta
Return newNumber
Else
beta += 1
newNumber = alpha + ZeroPad(beta, 2)
Return newNumber
End If
End Function
Private Shared Function ZeroPad(ByVal number As String, ByVal toLength As Integer) As String
ZeroPad = number
'add the necessary leading zeroes to build it up to the desired length.
Do Until Len(ZeroPad) >= toLength
ZeroPad = "0" & ZeroPad
Loop
End Function
I think you can do this by assuming your first character is the 'hundreds' and converting to a number and incrementing:
Private Function NextSerial(value As String) As String
Const chars As String = "0123456789ABCDEFGHJKLMNPQRSTUVWXYZ"
Dim numericValue As Integer = 100 * (chars.IndexOf(value.Substring(0, 1))) + Integer.Parse(value.Substring(1, 2))
numericValue += 1
Return chars.Substring(numericValue \ 100, 1) + (numericValue Mod 100).ToString.PadLeft(2, "0")
End Function
You should of course perform some error checking at the start of the function to make sure a valid serial number has been handed into the function. I would also put this function into a class and add functions such as isValid, SerialsRemaining and perhaps a function to retrieve a list of multiple serials.
I created constant strings that represent every available character in each digit position. I then used indexing to lookup the positions of the current serial number & moved one number forward to get the next serial. This will always provide the next serial until you run out of numbers.
Note: this code can easily be made more compact, but I left it as-is thinking it might be clearer.
Const charString1 As String = "0123456789ABCDEFGHJKLMNPQRSTUVWXYZ"
Const charString2 As String = "0123456789"
Const charString3 As String = "0123456789"
Public Function NextSerial(ByVal value As String) As String
' ensures the input is three chars long
Dim threenumber As String = Right("000" & value, 3)
Dim char1 As String = threenumber.Substring(0, 1)
Dim char2 As String = threenumber.Substring(1, 1)
Dim char3 As String = threenumber.Substring(2, 1)
Dim char1Pos As Integer = charString1.IndexOf(char1)
Dim char2Pos As Integer = charString2.IndexOf(char2)
Dim char3Pos As Integer = charString3.IndexOf(char3)
If char1Pos = -1 Or char2Pos = -1 Or char3Pos = -1 Then Throw New Exception("Invalid serial number format")
' move to next serial number
char3Pos += 1
If char3Pos > charString3.Length() - 1 Then
char3Pos = 0
char2Pos += 1
End If
If char2Pos > charString2.Length() - 1 Then
char2Pos = 0
char1Pos += 1
End If
If char1Pos > charString1.Length() - 1 Then Throw New Exception("Out of serial numbers!")
Return charString1.Substring(char1Pos, 1) & charString2.Substring(char2Pos, 1) & charString3.Substring(char3Pos, 1)
End Function
I suggest you use integer for all your check and calculation and only convert to serial number for display. It'll be a lot easier to know how many serial number are remaining.
Your serial number is similar to integer except everything over 100 is a letter instead of a number.
Note: It's very important to add error checking, this assumes that all input are valid.
Module Module1
Sub Main()
Console.WriteLine(SerialNumber.ConvertSerialNumberToInteger("D22"))
Console.WriteLine(SerialNumber.ConvertIntegerToSerialNumber(322))
Console.WriteLine(SerialNumber.GetAvailableSerialNumber("Z90"))
For Each sn As String In SerialNumber.GetNextSerialNumber("X97", 5)
Console.WriteLine(sn)
Next
Console.ReadLine()
End Sub
End Module
Class SerialNumber
Private Const _firstPart As String = "ABCDEFGHJKLMNPQRSTUVWXYZ"
Public Shared Function ConvertSerialNumberToInteger(ByVal serialNumber As String) As Integer
Return (_firstPart.IndexOf(serialNumber(0)) * 100) + Integer.Parse(serialNumber.Substring(1, 2))
End Function
Public Shared Function ConvertIntegerToSerialNumber(ByVal value As Integer) As String
Return _firstPart(value \ 100) & (value Mod 100).ToString("00")
End Function
Public Shared Function GetAvailableSerialNumber(ByVal serialNumber As String)
Dim currentPosition As Integer
Dim lastPosition As Integer
currentPosition = ConvertSerialNumberToInteger(serialNumber)
lastPosition = ConvertSerialNumberToInteger("Z99")
Return lastPosition - currentPosition
End Function
Public Shared Function GetNextSerialNumber(ByVal serialNumber As String, ByVal amount As Integer) As List(Of String)
Dim newSerialNumbers As New List(Of String)
Dim currentPosition As Integer
currentPosition = ConvertSerialNumberToInteger(serialNumber)
For i As Integer = 1 To amount
newSerialNumbers.Add(ConvertIntegerToSerialNumber(currentPosition + i))
Next
Return newSerialNumbers
End Function
End Class

Check String for identical Digits

I'm asking my users to enter a 4 - 6 digit numberic PIN. And I'd like to make sure users can't enter 0000 or 11111 or 333333. How can I check a string for 4 consecutive identical digits? I'm using vb.net.
See code snippet below:
Sub Main()
Dim a As String = "001111"
Dim b As String = "1123134"
Dim c As String = "1111"
Console.WriteLine(CheckConsecutiveChars(a, 4)) 'True => Invalid Pin
Console.WriteLine(CheckConsecutiveChars(b, 4)) 'False => Valid Pin
Console.WriteLine(CheckConsecutiveChars(c, 4)) 'True => Invalid Pin
Console.ReadLine()
End Sub
'maxnumber = maximum number of identical consecutive characters in a string
Public Function CheckConsecutiveChars(ByVal j As String, ByVal maxNumber As Integer) As Boolean
Dim index As Integer = 0
While ((index + maxNumber) <= j.Length)
If (j.Substring(index, maxNumber).Distinct.Count = 1) Then
Return True
End If
index = index + 1
End While
Return False
End Function
The method String.Distinct.Count() counts the number of distinct characters in a string. You cast your digit to a String and test for the number of different characters. If the result is 1 then the user has entered the same number.
Note: If you're using the Substring, you must check the length of the string first (is it long enough) to avoid exceptions.
This answer is similar to the accepted answer, but does not create lots of temporary strings in memory.
'maxnumber = maximum number of identical consecutive characters in a string
Public Function HasConsecutiveChars(ByVal j As String, ByVal maxNumber As Integer) As Boolean
Dim result As Boolean = False
Dim consecutiveChars As Integer = 1
Dim prevChar As Char = "x"c
For Each c in j
If c = prevChar Then
consecutiveChars += 1
If consecutiveChars >= maxNumber Then
result = True
Exit For
End If
Else
consecutiveChars = 1
End If
prevChar = c
Next
Return result
End Function

Decimal to binary for large number (>2253483438943167)

I have a VB.Net application that goes through a series of processes to decode a string, one problem with this is that I have found a function that converts from binary to decimal for any number, but I cannot find a function that will convert a supplied number (in string format) into a binary string. For reference, the binary to decimal conversion function is below:
Public Function baseconv(d As String)
Dim N As Long
Dim Res As Long
For N = Len(d) To 1 Step -1
Res = Res + ((2 ^ (Len(d) - N)) * CLng(Mid(d, N, 1)))
Next N
Return Str(Res)
End Function
What i would do if the number is less than 16*1e18 <-> can hold in a Uint64 :
1) store the number inside an unsigned 64 bits integer : num.
2) then just loop on each bit to test it :
mask = 1<<63
do
if ( num AND mask ) then ->> push("1")
else ->> push("0")
mask = mask >> 1
until mask = 0
(where push builds the output with a string concatenation, or, if performance matters, a StringBuilder, or it can be a stream,... )
what about this?
Module Module1
Sub Main()
Console.WriteLine(Convert.ToString(2253483438943167 * 5, 2))
Console.ReadKey()
End Sub
End Module
Try using the System.Numerics.BigInteger class like this:
Dim d As String
d = "2253483438943167"
Dim bi As BigInteger
bi = BigInteger.Parse(d)
Dim ba() As Byte
ba = bi.ToByteArray()
Dim s As String
Dim N As Long
Dim pad as Char
pad = "0"c
For N = Len(ba) To 1 Step -1
s = s + Convert.ToString(ba(N)).PadLeft(8, pad)
Next N
How about
Dim foo As BigInteger = Long.MaxValue
foo += Long.MaxValue
foo += 2
Dim s As New System.Text.StringBuilder
For Each b As Byte In foo.ToByteArray.Reverse
s.Append(Convert.ToString(b, 2).PadLeft(8, "0"c))
Next
Debug.WriteLine(s.ToString.TrimStart("0"c))
'10000000000000000000000000000000000000000000000000000000000000000

print output of a function in vb.net

Public Function random_key(ByVal lenght As Integer) As String
Randomize()
Dim s As New System.Text.StringBuilder("")
Dim b() As Char = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz".ToCharArray()
For i As Integer = 1 To lenght
Randomize()
Dim z As Integer = Int(((b.Length - 2) - 0 + 1) * Rnd()) + 1
s.Append(b(z))
Next
Return s.ToString
Console.WriteLine(s.ToString)
End Function
i wanna print it like
s=textbox1.text or somethhing...
What wrong with using Console.WriteLine?
Note that you should not put it behind the return statement in the method because code behind a return is unreachable.
Dim random As String = random_key(10)
Console.WriteLine(random)

Is there a way to force circular integer overflow in Excel VBA?

I'm trying to convert some Java code to Excel and the required hashcode function generates an overflow error, instead of wrapping to the negative
Function FnGetStringHashCode(ByVal str As String) As Integer
Dim result, i
FnGetStringHashCode = 17
For i = 1 To Len(str)
Dim c, a
c = Mid(str, i, 1)
a = AscW(c)
FnGetStringHashCode = 31 * FnGetStringHashCode + a
Next i
End Function
Is there a way of doing this in Excel VBA?
Although there is no built-in way to do this, the computation is simple:
Public Function coerceLongToInt(toCoerce As Long) As Integer
Const MIN_INT As Long = -32768
Const MAX_INT As Long = 32767
Const NUM_INTS As Long = MAX_INT - MIN_INT + 1
Dim remainder As Long
remainder = toCoerce Mod NUM_INTS
If remainder > MAX_INT Then
coerceLongToInt = remainder - NUM_INTS
ElseIf remainder < MIN_INT Then
coerceLongToInt = remainder + NUM_INTS
Else
coerceLongToInt = remainder
End If
End Function
This is the behavior you want, right?
?coerceLongToInt(-32769)
32767
?coerceLongToInt(-32768)
-32768
?coerceLongToInt(-1)
-1
?coerceLongToInt(0)
0
?coerceLongToInt(1)
1
?coerceLongToInt(32767)
32767
?coerceLongToInt(32768)
-32768
You would use it like this:
Function FnGetStringHashCode(ByVal str As String) As Integer
Dim result, i
FnGetStringHashCode = 17
For i = 1 To Len(str)
Dim c, a
c = Mid(str, i, 1)
a = AscW(c)
FnGetStringHashCode = coerceLongToInt(31 * CLng(FnGetStringHashCode) + a)
Next i
End Function
You need the 'CLng' call in there to prevent VBA from raising an overflow error when it computes the intermediate value (31 * [some integer >= 1058]).
I have modified a little the script of ours. The main difference is returning type of your function. Now it returns Variant. As decimal is a subset of Variant, and it can store bigger numbers than long I think it is a good solution (see VBA data types) - I do not know is it possible to explicitly return Decimal. Here is the script
Function FnGetStringHashCode(ByVal str As String) As Variant
Dim tmp As Variant, c As String, a As Integer, i As Integer
tmp = 17
For i = 1 To Len(str)
c = Mid$(str, i, 1)
a = AscW(c)
tmp = 31 * tmp + a
Next i
FnGetStringHashCode = tmp
End Function
And a little test routine
Sub test()
Debug.Print CStr(FnGetStringHashCode("dawdaedae"))
End Sub