Excel VBA Text to Columns Backwards with maximum # of columns - vba

Apples, Oranges, Strawberries, Pears, Almonds, Peanuts, Peaches
I would like to find "," from backwards (instrrev) and perform something similar to text to columns function in Excel, which would
#1 > Apples, Oranges
#2 > Apples | Oranges
perform action that takes #1 to #2.
However, I would like to have maximum columns of 5 (split into 5 pieces and the split-base character searched from backwards)
so that the top example would result in:
Apples, Oranges, Strawberries | Pears | Almonds | Peanuts | Peaches
Please keep in mind that it is possible for the text to have no commas, so I need to check if they exists first
Thanks for the help!

Try this, by putting your example text in a cell, selecting that cell and then running the below. You will need to test this, and possibly handle some scenarios yourself - but this code should get you going and works on your example.
Sub SplitIntoColumns()
Dim intMaxCols As Integer
Dim intCommaFoundPos As Integer
Dim intNumCommasFound As Integer
Dim strTextToCheck As String
Dim strFoundText As String
Dim intRowToWriteTo As Integer
Dim intColToWriteTo As Integer
'this should be max num of columns you want -1
intMaxCols = 4
'just putting the text into the activecell and running on that
strTextToCheck = ActiveCell
'row to write output to
intRowToWriteTo = 10
'column to write output to - it will go backwards from here
intColToWriteTo = 10
'find the comma
intCommaFoundPos = InStrRev(strTextToCheck, ",")
'if there is a comma
If intCommaFoundPos > 0 Then
'loop until you have looped the max columns number of times, or until there are no commas left in the string
Do Until (intNumCommasFound = intMaxCols) Or intCommaFoundPos = 0
'get comma position
intCommaFoundPos = InStrRev(strTextToCheck, ",")
'if there is still a comma
If intCommaFoundPos > 0 Then
'keep track of the number found
intNumCommasFound = intNumCommasFound + 1
'take everything to right of comma
strFoundText = Trim(Mid(strTextToCheck, intCommaFoundPos + 1, Len(strTextToCheck)))
'write to sheet, adjust next column number
ActiveSheet.Cells(intRowToWriteTo, intColToWriteTo) = strFoundText
intColToWriteTo = intColToWriteTo - 1
'change the text to check to not include the word just found
strTextToCheck = Left(strTextToCheck, intCommaFoundPos - 1)
End If
Loop
'if there is any text left, write to sheet
If Len(strTextToCheck) > 0 Then ActiveSheet.Cells(intRowToWriteTo, intColToWriteTo) = strTextToCheck
End If
End Sub

You can also implement it in formula:
=IF(LEN(A3)-LEN(SUBSTITUTE(A3,",",""))<5,SUBSTITUTE(A3,",","|"),REPLACE(A3,FIND("#",SUBSTITUTE(A3,",","#",LEN(A3)-LEN(SUBSTITUTE(A3,",",""))-4))+1,LEN(A3),SUBSTITUTE(MID(A3,FIND("#",SUBSTITUTE(A3,",","#",LEN(A3)-LEN(SUBSTITUTE(A3,",",""))-4))+1,LEN(A3)),",","|")))
with the string in A3
How it works:
Find out the number of "," in the string by subtracting length of comma-less string from full string.
if less than 5 commas then substitute all "," with "|"
if equal to or more than 5 commas then, find the character position of the 5th comma from right,and replace the string after that character position with the substituted string.

Related

How to divide line of text that has both text and numbers with $ sign in front of it?

I want to divide this array of texts into 3 divisions
SAMPLE TEXT:
Personal injury during holiday $10,000
Property damage $100,000
Car damage $10,000 for third party
Property damage $100,000 for properties located in the City area
$20,000 each and every policy
And it should be organized like this:
Division 1 - full text before numbers
Division 2 - Numbers, it always starts with $
Division 3 - full text after numbers
Note:
The number of words before and after the number is inconsistent. Only the $ sign is consistent.
You can use this, The code might look complex but by studying it you will understand it
Dim test As String = "your string here"
'Split the text into lines and store in array
Dim split1() As String = Split(test, vbLf)
Dim split2() As String
Dim split3() As String
For x As Integer = 0 To Ubound(split1) - 1
split2 = Split(split1(x))
For y As Integer = 0 To Ubound(split2) - 1
If split2(y).StartsWith("$") Then
For z As Integer = 0 To y - 1
split3(0) &= split2(z)
Next
split3(1) = split2(y)
If y < Ubound(split2) - 1 Then
For a As Integer = y + 1 To Ubound(split2) - 1
split3(2) &= split2(y)
Next
End If
End If
For b As Integer = 0 To 2
Console.WriteLine(split3(x))
' or you could use Textbox.Text += split3(x)
' Do whatever you want with those values here
'split3(0) = Text before $ sign
'split3(1) = Text with $ sign
'split3(2) = Text after $ sign
Next
Next
Next
Regex is ideal for this. I will show an example for one line but you can apply it to every line in a loop.
Dim str = "Car damage $10,000 for third party"
'Create regex which matches three groups:
'Group 1: (.*) ==> matches any characters
'Group 2: (\$[\d,]+) ==> matches $ followed by one or more digits and/or comma (,)
'Group 3: (.*) ==> matches any characters
Dim regex = New Regex("(.*)(\$[\d,]+)(.*)")
Dim match = regex.Match(str)
'Get values for all groups, skipping the first one which matches the whole string.
Dim parts = match.Groups.Cast(Of Group).Skip(1).Select(Function(g) g.Value).ToArray()
You get this array as a result:

check if string contains specific integer

I have a grid view that has a column containing strings (Middle column).
On the rowDataBound event I want to loop through the column looking for the integer it contains and then display a value in the first column.
I know that the integer range will be 1 to 63 so I can use a FOR loop to loop through the numbers. Here is what I have so far.
For x As Integer = 1 To 63
If CType(e.Row.Cells(2).FindControl("lblTagName"), Label).Text Then
End If
Next
The problem I am having is using contains. I cant use the following as it would also be true for the number 1, 10, 11 etc when x = 1.
For x As Integer = 1 To 63
If CType(e.Row.Cells(2).FindControl("lblTagName"), Label).Text.Contains(x) Then
End If
Next
How do I make sure it only gets one result per number? i.e x = 6 would return UMIS.75OPTR6GROSSMARGIN.F_CV and not all the other strings that contain the number 6.
UPDATE - based on some answers I may not of explained this very well. I want to loop through the gridview and if the number 1 is found and only the number 1 in the second column, not 10 etc then I want to display "Run 1" in the first column. So when x = 10 it will show "Run 10" and so on.
UPDATE 2 - its definatley my explanation, apologies.
The resultant grid view would look like this.
The order of the second column is not set and is not in order.
You'd have to check the entire text of the label to determine whether it is only 1, and not 10, 11, 12, 13, ... as well.
Also, in this case you should use DirectCast rather than CType. CType is only used when converting to different types that include conversion operators, here you are always dealing with a label.
For x As Integer = 1 To 63
If String.Equals(DirectCast(e.Row.Cells(2).FindControl("lblTagName"), Label).Text, "UMIS.75OPTR" & x & "GROSSMARGIN.F_CV", StringComparison.OrdinalIgnoreCase) Then
'Do your stuff.
End If
Next
You might want to think if doing it the other way around. Get the list of numbers in your string with a regular expression match.
Dim s As String = "asd12asdasd.sdf3sdf"
For Each m As System.Text.RegularExpressions.Match In System.Text.RegularExpressions.Regex.Matches(s, "[\d]*")
If m.Success AndAlso Not String.IsNullOrEmpty(m.Value) Then
' m.Value
End If
Next
With that list of number, you can check if it's between 1 and 63.
If your string have the same suffix/prefix, just remove them to show you what the number is.
Dim s As String = "UMIS.75OPTR12GROSSMARGIN.F_CV"
Dim number As String = s.Replace("UMIS.75OPTR", "").Replace("GROSSMARGIN.F_CV", "")
Go backwards in a Do Until Loop:
Dim bolFoundMatch As Boolean = False
Dim intCursor As Integer = 63
Do Until (bolFoundMatch OrElse intCursor = 0)
If CType(e.Row.Cells(2).FindControl("lblTagName"), Label).Text.Contains(intCursor) Then
'Anything you want to do when you find your match.
'This will ensure your loop exits.
bolFoundMatch = True
End If
intCursor -= 1
Loop

VBA Split string and convert to Int

I have an Excel sheet where I have data in a column J4:J163, Each cell contains a string e.g. J4 = "1 6, 8 18, 20 24"
Using VBA I want to use the Split function to separate on the delimiter ','
then convert string values e.g. "1 6, 8 18, 20 24" into integers. Which should result into something like this '1 6' '8 18' '20 24'
I want to iterate through each two integer values subtracting like so
1-6 = 5
8-18 = 10
20-24 = 4
Each time adding these results to a variable i.e. 'total'
Depending on how many subtractions have been performed increment a variable, cnt++, in this case 3 times, (total + cnt).
total = 22
This result calculated from cell J4 i.e. 22 should be inputted into L4.
The result from J5 should be inputted into L5 etc.
Hope this makes sense.
Below is a very bare pseudo code, (newbie to VBA) your guidance would be well received.
Sub CalcHrs()
'Variables
Dim wrdArray() As String
Dim textString As String
Dim total As Integer 'substration results accumulation
Dim cnt As Integer 'for loop iteration count
' Grab String
textString = Range("J4")
' Place string into Array and Split
wrdArray() = Split(textString)
'Loop to convert string array to int array
'Some loop (i < array.length, bla bla)
'array index 0 - array index 1 place result into 'total'
'iterate through until length of array is reached, while cnt++
'place result of total + cnt into cell "L4"
'Move onto cell "J5" until "J163"
End Sub
Like somebody writted up. It's not a free "write-my-code" service, You should try yourself and If your code doesn't work then You can post it here to get help.
I will give you some tips:
Split the cell value like this: Split (Cell, ",")
Iterate the array result of this Split with for-each and split each value like this: Split(value, " ")
Add 1 to the normal count and add ABS(cint(value1) - cint(value2)) to the total count. Value1 and Value2 are the values retorned by the second split.

Extract 5-digit number from one column to another

I need help with extracting 5-digit numbers only from one column to another in Excel 2010. These numbers can be in any position of the string (beginning of the string, anywhere in the middle, or at the end). They can be within brackets or quotes like:
(15478) or "15478" or '15478' or [15478]
I need to ignore any numbers that are less than 5 digits and include numbers that start with 1 or more leading zeros (like 00052, 00278, etc.) and ensure that leading zeros are copied over to the next column. Could someone help me with either creating a formula or UDF?
Here is a formula-based alternative that will extract the first 5 digit number found in cell A1. I tend to prefer reasonably simple formula solutions over VBA in most situations as formulas are more portable. This formula is an array formula and thus must be entered with Ctrl+Shift+Enter. The idea is to split the string up into every possible 5 character chunk and test each one and return the first match.
=MID(A1,MIN(IF(NOT(ISERROR(("1"&MID(A1,ROW(INDIRECT("R1C[1]:R"&(LEN(A1)-4)&"C[1]",FALSE)),5)&".1")*1))*ISERROR(MID(A1,ROW(INDIRECT("R1C[1]:R"&(LEN(A1)-4)&"C[1]",FALSE))+5,1)*1)*ISERROR(MID(A1,ROW(INDIRECT("R1C[1]:R"&(LEN(A1)-4)&"C[1]",FALSE))-1,1)*1),ROW(INDIRECT("R1C[1]:R"&(LEN(A1)-4)&"C[1]",FALSE)),9999999999)),5)
Let's break this down. First we have an expression I used twice to return an array of numbers from 1 up to 4 less than the length of your initial text. So if you have a string of length 10 the following will return {1,2,3,4,5,6}. Hereafter the below formula will be referred to as rowlist. I used R1C1 notation to avoid potential circular references.
ROW(INDIRECT("R1C[1]:R"&(LEN(A1)-4)&"C[1]",FALSE))
Next we will use that array to split the text into an array of 5 letter chunks and test each chunk. The test being performed is to prepend a "1" and append ".1" then verify the chunk is numeric. The prepend and append eliminate the possibility of white space or decimals. We can then check the character before and the character after to make sure they are not numbers. Hereafter the below formula will be referred to as isnumarray.
NOT(ISERROR(("1"&MID(A1,rowlist,5)&".1")*1))
*ISERROR(MID(A1,rowlist+5,1)*1)
*ISERROR(MID(A1,rowlist-1,1)*1)
Next we need to find the first valid 5 digit number in the string by returning the current index from a duplicate of the rowlist formula and returning a large number for non-matches. Then we can use the MIN function to grab that first match. Hereafter the below will be referred to as minindex.
MIN(IF(isnumarray,rowlist,9999999999))
Finally we need to grab the numeric string that started at the index returned by the MIN function.
MID(A1,minindex,5)
The following UDF will return the first five digit number in the string, including any leading zero's. If you need to detect if there is more than one five digit number, the modifications are trivial. It will return a #VALUE! error if there are no five-digit numbers.
Option Explicit
Function FiveDigit(S As String, Optional index As Long = 0) As String
Dim RE As Object
Set RE = CreateObject("vbscript.regexp")
With RE
.Pattern = "(?:\b|\D)(\d{5})(?:\b|\D)"
.Global = True
FiveDigit = .Execute(S)(index).submatches(0)
End With
End Function
As you may see from the discussion between Mark and myself, some of your specifications are unclear. But if you would want to exclude decimal numbers, when the decimal portion has five digits, then the regex pattern in my code above should be changed:
.Pattern = "(?:\d+\.\d+)|(?:\b|\D)(\d{5})(?:\b|\D)"
I just wrote this UDF for you , basic but will do it...
It will find the first 5 consecutive numbers in a string, very crude error checking so it just says Error if anything isn't right
Public Function GET5DIGITS(value As String) As String
Dim sResult As String
Dim iLen As Integer
sResult = ""
iLen = 0
For i = 1 To Len(value)
If IsNumeric(Mid(value, i, 1)) Then
sResult = sResult & Mid(value, i, 1)
iLen = iLen + 1
Else
sResult = ""
iLen = 0
End If
If iLen = 5 Then Exit For
Next
If iLen = 5 Then
GET5DIGITS = Format(sResult, "00000")
Else
GET5DIGITS = "Error"
End If
End Function

excel 2007: append certain characters to value in a column to make it proper lenght

I have following values in a column :
123
456
789
65
1
I want to append correct number of zeros in all the values in that column such that the total length of character is 5.
00123
00456
00789
00065
00001
How do I do that?
If there is one number per cell, you can do this easily by changing the format to "Custom."
Right-click on the cells you would like to format.
From the context menu, choose "Format cells"
Choose the Custom category.
Over the word "General," in the Type textbox, enter 00000. (This tells Excel to print with
leading 0s).
Click OK.
If the number is bigger than five digits, it will print all of the digits.
===EDIT===
You explained that these were all in one cell. #paulmorriss has an excellent Excel-function-only solution, but let me proffer a VBA solution as an alternative:
Sub Macro1()
Dim txt As String
Dim asWords() As String
Dim zeros As String
txt = vbNullString
asWords = Split(Range("A1").Value) 'asWords(0)="123" etc.
For i = 0 To UBound(asWords) ' emulate StrDup (missing in VBA)
zeros = vbNullString
For j = Len(asWords(i)) + 1 To 5: zeros = zeros + "0": Next j
txt = txt + zeros + asWords(i) + " "
Next i
Range("B1").Value = txt 'Places answer in B1
End Sub
If the value you specify is in cell A1 then put the following formulae in B1 to K1. The value in K1 is what you need. You could specify one massive formula, but it's easier for people maintaining the spreadsheet to see what's going on if it's split up like this.
in B1 =TEXT(VALUE(LEFT(A1,SEARCH(" ",A1))),"000000")
in C1 =RIGHT(A1,LEN(A1)-SEARCH(" ",A1))
etc. =TEXT(VALUE(LEFT(C1,SEARCH(" ",C1))),"000000")
=RIGHT(C1,LEN(C1)-SEARCH(" ",C1))
=TEXT(VALUE(LEFT(E1,SEARCH(" ",E1))),"000000")
=RIGHT(E1,LEN(E1)-SEARCH(" ",E1))
=TEXT(VALUE(LEFT(G1,SEARCH(" ",G1))),"000000")
=RIGHT(G1,LEN(G1)-SEARCH(" ",G1))
=TEXT(I1,"000000")
=B1&" "&D1&" "&F1&" "&H1&" "&J1