How to compare numbers as string?
I want to compare f.ex. 2 and 10. When i sort them in Excel in ascending order 2 is before 10, but when i compare in VBA those two 10 seems to be lower number than 2. I'm using strcomp function. I need to compare them as strings beacuse it's a part of bigger program that's searching for the identical strings in excel columns. Strings can be normal strings, numbers and number-ish strings as "12-131xxx".
Mnich, with StrComp, either vbBinaryCompare or vbTextCompare will give you the returns you're currently getting. When Excel sorts numbers/integers, it sorts as you would expect, but when sorting numbers as strings, it uses a textual comparison; so all numbers starting with 1, even 111, will be ranked lower than 2. As Comintern mentions, you have to add leading zeros to get away with this.
Or, perhaps, you replied one number comparison before you ranked the strings, you could try a Function to extract the numbers, then let that weigh your decision:
'pass in array from main stuff
Function StackOverflow(arr())
Dim arr_NewStr() As String
Dim x As Integer
Dim i As Integer
ReDim arr_NewStr(1 To UBound(arr))
x = 1
For i = 1 To UBound(arr)
Do
If IsNumeric(Mid(arr(i), x, 1)) Then
arr_NewStr = arr_NewStr & Mid(arr(i), x, 1)
End If
x = x + 1
Loop Until x = Len(arr(i))
Next
'clean up
x = vbEmpty: i = vbEmpty
'pass somewhere, or make "arr" public
End Function
Related
I currently have a cell with some values, separated by commas. I wish to sort them in ascending order.
Sample Input (Value in a single cell):
Sample Output (Value in a single cell):
I have seen many answers when it comes to sorting rows and columns, but I can't seem to sort the values in a single cell in ascending order. Is it possible to sort the values in a single cell in ascending order? Or is there a workaround for this?
Some explanation/documentation would be appreciated as I'm a beginner at VBA. Thank you for your help.
Please try to split data in a single cell by comma, then sorting it and combine all of them together?
The comments provide you with numerous ways to sort an array. Rightly or wrongly, I've provided my own flavour on an old VBA topic along with the extended piece of outputting the string in a delimited format. Take it or leave it ...!
You should be able to refer to the below function directly from any given cell like you would any built-in function in Excel.
Public Function SplitAndSortAscending(ByVal strText As String, ByVal strDelimiter As String) As String
Dim arrData() As String, arrNewData() As String, i As Long, x As Long, y As Long
arrData = Split(strText, strDelimiter)
ReDim arrNewData(UBound(arrData))
For i = 0 To UBound(arrData)
For x = 0 To UBound(arrNewData)
If arrData(i) < arrNewData(x) Or arrNewData(x) = "" Then
For y = UBound(arrNewData) To x + 1 Step -1
arrNewData(y) = arrNewData(y - 1)
Next
arrNewData(x) = arrData(i)
Exit For
End If
Next
Next
For i = 0 To UBound(arrNewData)
SplitAndSortAscending = SplitAndSortAscending & strDelimiter & arrNewData(i)
Next
SplitAndSortAscending = Mid(SplitAndSortAscending, Len(strDelimiter) + 1)
End Function
If you have O365, you can use something like the below to achieve the same sort of thing. Take note, my implementation will take 1.0 and format it as a whole number, i.e. it will come out as 1.
=TEXTJOIN(",",TRUE,SORT(FILTERXML("<r><v>" & SUBSTITUTE(A1,",","</v><v>") & "</v></r>","//v")))
The assumption is that the example you provided is in cell A1.
The UDF and other solutions offered in other questions do not solve this problem. Perhaps it is the length of the strings, and then number of duplicates in my problem. (All numbers, separated by commas, 13 digits long, 2 to 3 unique numbers repeated approximately 20-40 times in a single cell.)
I reviewed the answers to this question but those answers didn't work properly with my data.
Is there a function or a formula that I can use to remove duplicate strings within a single cell?
If,
A1=10,10,10,10,11,11,12,12,12 (the actual numbers are 13 digits each and they are either 2 or 3 unique numbers that repeat. I just need to capture each unique number)
Is there a simple way like RemoveDups() that will remove the duplicates and leave just . A1=10,11,12? Or do I need to create a UDF?
Function RemoveDuplicates(v As Variant) As String
Dim aSplit As Variant, aUnique() As Variant, vMatch As Variant, a As Variant
aSplit = Split(v, ",")
ReDim Preserve aUnique(0 To x)
aUnique(0) = Application.WorksheetFunction.Rept("|^|", 20)
For Each a In aSplit
vMatch = Application.Match(Trim(a), aUnique, 0)
If IsError(vMatch) Then
x = x + 1
ReDim Preserve aUnique(0 To x)
aUnique(x) = Trim(a)
End If
Next a
RemoveDuplicates = Join(Filter(aUnique, aUnique(0), False), ",")
End Function
Good day everyone,
I am trying to find a smart solution of extracting 8 digits from a cell (unique ID). The problem here occurs that it might look like this:
112, 65478411, sale
746, id65478411, sale 12.50
999, 65478411
999, id65478411
Thats most of the cases, and probably all mentioned, so I basically need to find the 8 digits in the cell and extract them into different cell. Does anyone have any ideas? I though of eliminating the first characted, then check if the cell is starting with the id, eliminate it further but I understood that this is not the smart way..
Thank you for the insights.
Try this formula:
=--TEXT(LOOKUP(10^8,MID(SUBSTITUTE(A1," ","x"),ROW(INDIRECT("1:"&LEN(A1)-7)),8)+0),"00000000")
This will return the 8 digit number in the string.
To return just the text then:
=TEXT(LOOKUP(10^8,MID(SUBSTITUTE(A1," ","x"),ROW(INDIRECT("1:"&LEN(A1)-7)),8)+0),"00000000")
You can also write a UDF to accomplish this task, example below
Public Function GetMy8Digits(cell As Range)
Dim s As String
Dim i As Integer
Dim answer
Dim counter As Integer
'get cell value
s = cell.Value
'set the counter
counter = 0
'loop through the entire string
For i = 1 To Len(s)
'check to see if the character is a numeric one
If IsNumeric(Mid(s, i, 1)) = True Then
'add it to the answer
answer = answer + Mid(s, i, 1)
counter = counter + 1
'check to see if we have reached 8 digits
If counter = 8 Then
GetMy8Digits = answer
Exit Function
End If
Else
'was not numeric so reset counter and answer
counter = 0
answer = ""
End If
Next i
End Function
Here is an alternative:
=RIGHT(TRIM(MID(SUBSTITUTE(A1,",",REPT(" ",LEN(A1))),LEN(A4),LEN(A1))),8)
Replace all commas with spaces repeated the length of the string,
Then take the mid point starting from the length of the original string for the length of the string (ie second word in new string)
Trim out the spaces
take the right 8 chars to trim out any extra chars (like id)
I want to multiply two 100-Digit Numbers In Excel using matrix. The issue in Excel is that after 15-digit, it shows only 0. So, the output also need to be in a Matrix.
1st Number: "9999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999"
2nd Number: "2222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222"
Output: "22222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222217777777777777777777777777777777777777777777777777777777777777777777777777777777777777777777777777778"
This may be what OP was after. I thought I would try a naive multiplication method to see how long it would take to run. The answer is less than a second for two 100-digit numbers. You have to select the output range (i.e. A3:GR3 for a 200-digit result) and enter the formula containing the input ranges as an array formula using CtrlShiftEnter e.g.
=Multiply(A1:CV1,A2:CV2)
for two 100-digit numbers.
The method is basically just a simulation of school maths long multiplication, except that the intermediate rows are not stored but immediately added to the answer thus saving a lot of space.
The utility of it is obviously not that it is a replacement for the Karatsuba method, but it is a simple verifiable method which could be used for one-off calculations.
Currently limited to multiplication of rows containing more than one cell (so if you wanted to multiply by a single digit number, would have to enter it as e.g. 09).
Start of numbers
Middle of numbers
End of numbers
Function Multiply(rng1 As Variant, rng2 As Variant)
Dim arr() As Integer
Dim arrLength, r1Length, r2Length, carry, product, digit As Integer
Dim tot, totDigit, totCarry As Integer
Dim v1, v2 As Variant
v1 = rng1
v2 = rng2
r1Length = UBound(v1, 2)
r2Length = UBound(v2, 2)
arrLength = r1Length + r2Length
' Declare 1D array with enough space
ReDim arr(1 To arrLength)
' Loop over digits in first number starting from right
For i = r1Length To 1 Step -1
carry = 0
totCarry = 0
' Loop over digits in second number starting from right
For j = r2Length To 1 Step -1
' Calculate next digit in intermediate values (i.e. one row of long multiplication)
product = v1(1, i) * v2(1, j) + carry
digit = product Mod 10
carry = Int(product / 10)
' Calculate next digit in final values (i.e. totals line of long multiplication)
tot = arr(i + j) + digit + totCarry
arr(i + j) = tot Mod 10
totCarry = Int(tot / 10)
Next j
' Process final carry
arr(i) = carry + totCarry
Next i
' Return as an array
Multiply = arr
End Function
OK it might work like this:-
(1) You need to concatenate your numbers into a string because that's what you need as the input to your function. Native Excel won't do concatenation on arrays so you need a UDF like this one. So B2 contains
=concat(D1:G1)
(2) The output from the function is a string so you need to split it back into separate cells. You could use another UDF or a formula like this one copied across:-
=IF(COLUMNS($C3:C3)>LEN($B$3),"",VALUE(MID($B3,COLUMNS($C3:C3),1)))
So for the simple example it would look like this:-
But I might have got the wrong end of the stick completely.
Place your arrays into A1:A100 and B1:B100, then use three formulas:
1) In C2:C200 enter this as an array formula:
=MMULT(IFERROR(INDEX(A1:A100*TRANSPOSE(B1:B100),(ROW(INDIRECT("1:"&ROWS(A1:A100)*2-1))>0)+TRANSPOSE(ROW(INDIRECT("1:"&ROWS(A1:A100))))-1,MOD(ROW(INDIRECT("1:"&ROWS(A1:A100)*2-1))-TRANSPOSE(ROW(INDIRECT("1:"&ROWS(A1:A100)))),ROWS(A1:A100)*2-1)+1),0),SIGN(A1:A100+1))
2) In D1 enter =C1+INT(D2/10) and fill down to D200.
3) In E1 enter =MOD(D1,10) and fill down to D200.
E1:E200 will contain the answer.
If I am having G4ED7883666 and I want the output to be 7883666
and I have to apply this on a range of cells and they are not the same length and the only common thing is that I have to delete anything before the number that lies before the alphabet?
This formula finds the last number in a string, that is, all digits to the right of the last alpha character in the string.
=RIGHT(A1,MATCH(99,IFERROR(1*MID(A1,LEN(A1)+1-ROW($1:$25),1),99),0)-1)
Note that this is an array formula and must be entered with the Control-Shift-Enter keyboard combination.
How the formula works
Let's assume that the target string is fairly simple: "G4E78"
Working outward from the middle of the formula, the first thing to do is create an array with the elements 1 through 25. (Although this might seem to limit the formula to strings with no more than 25 characters, it actually places a limit of 25 digits on the size of the number that may be extracted by the formula.
ROW($1:$25) = {1;2;3;4;5;6;7; etc.}
Subtracting from this array the value of (1 + the length of the target string) produces a new array, the elements of which count down from the length of string. The first five elements will correspond to the position of the characters of the string - in reverse order!
LEN(A1)+1-ROW($1:$25) = {5;4;3;2;1;0;-1;-2;-3;-4; etc.}
The MID function then creates a new array that reverses the order of the characters of the string.
For example, the first element of the new array is the result of MID(A1, 5, 1), the second of MID(A1, 4, 1) and so on. The #VALUE! errors reflect the fact that MID cannot evaluate 0 or negative values as the position of a string, e.g., MID(A1,0,1) = #VALUE!.
MID(A1,LEN(A1)+1-ROW($1:$25),1) = {"8";"7";"E";"4";"G";#VALUE!;#VALUE!; etc.}
Multiplying the elements of the array by 1 turns the character elements of that array to #VALUE! errors as well.
=1*MID(A1,LEN(A1)+1-ROW($1:$25),1) = {"8";"7";#VALUE!;"4";#VALUE!;#VALUE!;#VALUE!; etc.}
And the IFERROR function turns the #VALUES into 99, which is just an arbitrary number greater than the value of a single digit.
IFERROR(1*MID(A1,LEN(A1)+1-ROW($1:$25),1),99) = {8;7;99;4;99;99;99; etc.}
Matching on the 99 gives the position of the first non-digit character counting from the right end of the string. In this case, "E" is the first non-digit in the reversed string "87E4G", at position 3. This is equivalent to saying that the number we are looking for at the end of the string, plus the "E", is 3 characters long.
MATCH(99,IFERROR(1*MID(A1,LEN(A1)+1-ROW($1:$25),1),99),0) = 3
So, for the final step, we take 3 - 1 (for the "E) characters from the right of string.
RIGHT(A1,MATCH(99,IFERROR(1*MID(A1,LEN(A1)+1-ROW($1:$25),1),99),0)-1) = "78"
One more submission for you to consider. This VBA function will get the right most digits before the first non-numeric character
Public Function GetRightNumbers(str As String)
Dim i As Integer
For i = Len(str) To 0 Step -1
If Not IsNumeric(Mid(str, i, 1)) Then
Exit For
End If
Next i
GetRightNumbers = Mid(str, i + 1)
End Function
You can write some VBA to format the data (just starting at the end and working back until you hit a non-number.)
Or you could (if you're happy to get an addin like Excelicious) then you can use regular expressions to format the text via a formula. An expression like [0-9]+$ would return all the numbers at the end of a string IIRC.
NOTE: This uses the regex pattern in James Snell's answer, so please upvote his answer if you find this useful.
Your best bet is to use a regular expression. You need to set a reference to VBScript Regular Expressions for this to work. Tools --> References...
Now you can use regex in your VBA.
This will find the numbers at the end of each cell. I am placing the result next to the original so that you can verify it is working the way you want. You can modify it to replace the cell as soon as you feel comfortable with it. The code works regardless of the length of the string you are evaluating, and will skip the cell if it doesn't find a match.
Sub GetTrailingNumbers()
Dim ws As Worksheet
Dim rng As Range
Dim cell As Range
Dim result As Object, results As Object
Dim regEx As New VBScript_RegExp_55.RegExp
Set ws = ThisWorkbook.Sheets("Sheet1")
' range is hard-coded here, but you can define
' it programatically based on the shape of your data
Set rng = ws.Range("A1:A3")
' pattern from James Snell's answer
regEx.Pattern = "[0-9]+$"
For Each cell In rng
If regEx.Test(cell.Value) Then
Set results = regEx.Execute(cell.Value)
For Each result In results
cell.Offset(, 1).Value = result.Value
Next result
End If
Next cell
End Sub
Takes the first 4 digits from the right of num:
num1=Right(num,4)
Takes the first 5 digits from the left of num:
num1=Left(num,5)
First takes the first ten digits from the left then takes the first four digits from the right:
num1=Right(Left(num, 10),4)
In your case:
num=G4ED7883666
num1=Right(num,7)