Split a float number at decimal point using Excel VBA - excel

I am trying to split a number at the decimal point and store the two parts in two strings.
E.g. 12.345 to be stored as S1 = 12 and S2 = 345
E.g. 12.3450 to be stored as S1 = 12 and S2 = 345
Can someone guide me with excel VBA for this?

You can use the split function to do this:
Dim splitnnum
Dim num as Double
num = 111.222
splitnum = Split(Str(num), ".")
s1 = splitnum(0)
s2 = splitnum(1)

This will split at the decimal and assign each part to a string.
Dim x as Variant
Dim num1 as String, num2 as String
x = Split(Str(12.345), ".")
num1 = x(Lbound(x,1))
num2 = x(Ubound(x,1))

The easiest way to do it would likely be something like:
Dim lHolder as Double
Dim lWhole as Double
Dim lRemain as Double
lHolder = 12.345 ' Or whatever variable you have your number stored in
lWhole = Fix(lHolder)
lRemain = lHolder - lWhole
You can then round lRemain as needed. For example
Round(lRemain, 5) ' Rounds out to 5 decimal places
Will return .345

This breaks your number at decimal point
mynumber = 111.222
splitmynumber = Split(Str(mynumber ), ".")
'This is an array storing 2 number
numberbeforedecimal = val(splitmynumber (0))
numberafterdecimal = val(splitmynumber (1))
Answer : 111 & 222

Related

Recursive function to convert from decimal to binary

My code has a problem with conversion of the number 3
I would like to write a function which converts a decimal number into a binary one. The principle of recursion must be used. I have already written the following code.
Function recursive(number As Integer) As String
Dim result As String
If number > 0 Then
Dim binaryNumber As String
Dim digit As Integer
binaryNumber = recursive(number / 2)
digit = number Mod 2
result = result & binaryNumber & digit
End If
recursive = result
End Function
Right result:
Input: 10
Output: 1010
Wrong result:
Input: 3
Output: 101
It also works reasonably well, but I get a wrong result when I try to convert the decimal number 3. Where is the error?
Function recursive(number As Integer) As String
Dim result As String
If number > 0 Then
Dim binaryNumber As String
Dim digit As Integer
digit = number Mod 2
number = Int(number / 2)
binaryNumber = recursive(number)
result = result & binaryNumber & digit
End If
recursive = result
End Function

VBA generate a code

there. I made this code that replaces a character for two number (e.g. 0 = 10; 1 = 11; 2 = 12; ...) and everything works fine except for the first element (the zero element). So, if I put "010a4" string on cell A1 and use my formula "=GENERATECODE(A1)", my expected return value is "1011102014" but I've got a "110111102014" string. So, only zero value occur this error and I can't figured out why. Any thoughts?
My code:
Function GENERATECODE(Code As String)
Dim A As String
Dim B As String
Dim i As Integer
Const AccChars = "0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ"
Const RegChars = "1011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071"
For i = 1 To Len(AccChars)
A = Mid(AccChars, i, 1)
B = Mid(RegChars, 2 * i - 1, 2)
Code = Replace(Code, A, B)
Next
GENERATECODE = Code
End Function
Your problem is that your code first change each 0 to 10 then each 1 to 11. So each 0 give you 10 then 110.
If you want to keep the same kind of algorithm (which might not be a good choice), you need to change AccChars and RegChars so that a character is never replaced by a string that can give a character found later on the AccChars String. In your case just replace Const AccChars = "012 ... per Const AccChars = "102 ... and Const RegChars = "101112 ... per Const RegChars = "111012 ...
But it might be better to change your algorithm altogether. I would first suggest to not use in place editing of the string, but rather to use 2 Strings.
In addition to being incorrect, your current code is inefficient since it involves scanning over the code string multiple times instead of just once. Simply scan over the string once, gathering the substitutions into an array which is joined at the end:
Function GENERATECODE(Code As String) As String
Dim codes As Variant
Dim i As Long, n As Long
Dim c As String
n = Len(Code)
ReDim codes(1 To n)
For i = 1 To n
c = Mid(Code, i, 1)
Select Case c
Case "0" To "9":
codes(i) = "1" & c
Case "a" To "z":
codes(i) = Asc(c) - 77
Case "A" To "Z":
codes(i) = Asc(c) - 19
Case Else:
codes(i) = "??"
End Select
Next i
GENERATECODE = Join(codes, "")
End Function
Example:
?generatecode("010a4")
1011102014
The point of the two offsets is that you want "a" to map to 20 and "A" to map to 46. Note Asc("a") - 77 = 97 - 77 and Asc("A") - 19 = 65-19 = 46.

Replace a string with a format string

I have the following input:
Dim str_format as string = "XXXXX00000"
Dim str as string = "INV"
Dim int as integer = "56"
How can I replace XXXXX with INV and replace 00000 with 56?
For the example above the result should be INVXX00056.
X can only replace with alphabet and 0 can only replace with integer, if str has more than five alphabet. The extra alphabets will be thrown away because str_format only has five X. The same algorithm is true for the integer.
Example 2
Dim str_format as string = "XXX00000"
Dim str as string = "ABCD"
Dim int as integer = 654321
Expected result: ABC54321
Process:
1. ABCD XXX00000 654321
2. ABC DXX000006 54321
3. AB CDX00065 4321
4. A BCD00654 321
5. ABC06543 21
6. ABC65432 1
7. ABC54321
As Spidey mentioned... show some code. That said the process you describe is a bit long-winded.
The Letter part of the solution can be done by grabbing the first 3 characters of str using Left(str,3) this will bring in the leftmost 3 character (if there are less it will get what is there). Then check that you have 3 characters using str.Length(). If the length is less than 3 then append the appropriate number of 'X'.
The Numeric part can be done in a similar way. Your int is actually a string in your code above. If it was a real integer you can cast it to string. Use Right(int,5). Again check to see you have 5 digits and if not prepend with appropriate number of 0.
Have a go... if you run into problems post your code and someone is bound to help.
UPDATE
As there have been actual answers posted here is my solution
Function FormatMyString(str As String, num as String) As String
Dim result As String
result = Left(str,3).PadRight(3, "X"c).ToUpper() & Right(num,5).PadLeft(5, "0"c)
Return result
End Function
UPDATE 2
based on Wiktors answer... made an amendment to my solution to cope with different formats
Function FormatMyString(str As String, num as String, alpha as Integer, digits as Integer) As String
Dim result As String
result = Left(str, alpha).PadRight(alpha, "X"c).ToUpper() & Right(num, digits).PadLeft(digits, "0"c)
Return result
End Function
To use...
FormatMyString("ABCDE", "56",3 5) will return ABC00056
FormatMyString("ABCDE", "123456",4 3) will return ABCD456
FormatMyString("AB", "123456",4 3) will return ABXX456
Here is a possible solution that just uses basic string methods and PadLeft/PadRight and a specific method to count occurrences of specific chars in the string. It assumes the format string can only contain X and 0 in the known order.
Public Function CountCharacter(ByVal value As String, ByVal ch As Char) As Integer
Return value.Count(Function(c As Char) c = ch)
End Function
Public Sub run1()
Dim str_format As String = "XXXXX00000" '"XXX00000"
Dim str As String = "INV"
Dim int As Integer = 56 ' ABC54321
Dim xCnt As Integer = CountCharacter(str_format, "X")
Dim zCnt As Integer = CountCharacter(str_format, "0")
Dim result As String
If xCnt > str.Length Then
result = str.PadRight(xCnt, "X")
Else
result = str.Substring(0, xCnt)
End If
If zCnt > int.ToString().Length Then
result = result & int.ToString().PadLeft(zCnt, "0")
Else
result = result & int.ToString().Substring(int.ToString().Length-zCnt
End If
Console.WriteLine(result)
End Sub
Output for your both scenarios is as expected.
Take a look at this sample
Dim str_format As String = str_format.Replace("XXX", "ABC")
Msgbox(str_format )
As we assume that the X is 3 only. I dont want to give you more it is a start and everything will be easy.
If that kind of format is fix I mean the number of X will go or down then you can make a conditional statement based on the length of string

Replace one character with two using replace function

I am trying to convert accented characters to regular characters. Some characters need to be replaced with two characters. I tried MID(string,i,2).
Function ChangeAccent(thestring As String)
Dim A As String * 1
Dim B As String * 1
Dim C As String * 1
Dim D As String * 1
Dim i As Integer
Const LatChars="ßÄÖÜäöü"
Const OrgChars= "SSAEOEUEaeoeue"
For i = 1 To Len(LatChars)
A = Mid(LatChars, i, 1)
B = Mid(OrgChars, i, 2)
thestring = Replace(thestring, A, B)
Next
Const AccChars="ŠŽšžŸÀÁÂÃÄÅÇÈÉÊËÌÍÎÏÐÑÒÓÔÕÖÙÚÛÜÝàáâãäåçèéêëìíîïðñòóôõöùúûüýÿ"
Const RegChars= "SZszYAAAAAACEEEEIIIIDNOOOOOUUUUYaaaaaaceeeeiiiidnooooouuuuyy"
For i = 1 To Len(AccChars)
C = Mid(AccChars, i, 1)
D = Mid(RegChars, i, 1)
thestring = Replace(thestring, C, D)
Next
ChangeAccent = thestring
End Function
The code is working for one by one replacement (1 character by 1 character).
I want to replace one character in the variable LatChars with 2 characters in OrgChars. i.e ß with SS, Ä with AE and so on.
The Mid(OrgChars, i,2) is not extracting two characters.
Minor changes:
Dim B As String * 2
B = Mid(OrgChars, i * 2 - 1, 2)
Option Explicit
Function ChangeAccent(thestring As String)
Dim A As String * 1
Dim B As String * 2
Dim C As String * 1
Dim D As String * 1
Dim i As Integer
Const LatChars = "ßÄÖÜäöü"
Const OrgChars = "SSAEOEUEaeoeue"
For i = 1 To Len(LatChars)
A = Mid(LatChars, i, 1)
B = Mid(OrgChars, i * 2 - 1, 2)
thestring = Replace(thestring, A, B)
Next
Const AccChars = "ŠŽšžŸÀÁÂÃÄÅÇÈÉÊËÌÍÎÏÐÑÒÓÔÕÖÙÚÛÜÝàáâãäåçèéêëìíîïðñòóôõöùúûüýÿ"
Const RegChars = "SZszYAAAAAACEEEEIIIIDNOOOOOUUUUYaaaaaaceeeeiiiidnooooouuuuyy"
For i = 1 To Len(AccChars)
C = Mid(AccChars, i, 1)
D = Mid(RegChars, i, 1)
thestring = Replace(thestring, C, D)
Next
ChangeAccent = thestring
End Function
B = Mid(OrgChars, i,2)
Should probably be
B = Mid(OrgChars, i*2-1,2)
One method is to use two arrays. One that contains the character you wish to replace and the other its replacement. This method depends on both arrays being in sync with one another. Element 1 in the first array must match element 1 in the second, and so on.
This method allows you to ignore the string lengths. There is no longer any need to process 1 and 2 character replacement strings separately. This code can also scale to 3, 4 or more character replacements without a logic change.
I've used the split function to build the arrays. I find this saves time when typing out the code. But you may prefer to define the elements individually, which is arguably easier to read.
Example
Sub Demo001()
' Demos how to replace special charaters of various lenghts.
Dim ReplaceThis() As String ' Array of characters to replace.
Dim WithThis() As String ' Array of replacement characters.
Dim c As Integer ' Counter to loop over array.
Dim Sample As String ' Contains demo string.
' Set up demo string.
Sample = "ß - Ä - Š"
' Create arrays using split function and comma delimitor.
ReplaceThis = Split("ß,Ä,Š", ",")
WithThis = Split("SS,AE,S", ",")
' Loop over replacements.
For c = LBound(ReplaceThis) To UBound(ReplaceThis)
Sample = Replace(Sample, ReplaceThis(c), WithThis(c))
Next
' Show result.
MsgBox Sample
End Sub
Returns
SS - AE - S
EDIT: Answer rewritten as first attempt misunderstood - and did not answer - op question

Dividing a string in groups of two

I have a Hex string that has a value like
26C726F026C426A1269A26AB26F026CC26E226C726E226CD
I was wondering how to split it into a string array, where each index of the array holds a group of 2 of those chars.
Example:
string(0)=26,string(1)=C7,string(2) = 26,string (3) = F0, and so on.
How can I do this?
Dim MyList as New List(Of String)
Dim s as String = "26C726F026C426A1269A26AB26F026CC26E226C726E226CD"
For x as Integer = 0 to s.Length - 1 step 2
MyList.Add(s.substring(x,2))
Next
You can get it with MyList(0), MyList(1) or etc

Resources