How can I set up a macro that will strip the letters from #####XX in column I and put them in to column L same row? Thanks!
Assuming you're working with the first sheet and you're always stripping off the last two characters while leaving the first 5 characters, the following code will work:
Public Sub StripOff()
Dim iRow as Integer
iRow = 2 'Assuming row 1 is headers, else make this 1
While Sheets(1).Range("I" + Cstr(iRow)).Value <> ""
Sheets(1).Range("L" + CStr(iRow)).Value = Right(Sheets(1).Range("I" + Cstr(iRow)).Value, 2)
Sheets(1).Range("I" + Cstr(iRow)).Value = Left(Sheets(1).Range("I" + Cstr(iRow)).Value, 5)
iRow = iRow + 1
Wend
End Sub
The operative words I'm understanding from your question are Cutting and strip. To my mind, this means that the last two letters are permanently removed from column I and placed in column L.
Sub cut2right()
Dim v As Long, vPFXS As Variant, vSFXS As Variant
With Worksheets("Sheet6")
vPFXS = .Range(.Cells(2, "I"), .Cells(Rows.Count, "I").End(xlUp))
ReDim vSFXS(1 To UBound(vPFXS), 1 To 1)
For v = LBound(vPFXS, 1) To UBound(vPFXS, 1)
If Len(vPFXS(v, 1)) > 1 Then
vSFXS(v, 1) = Right(vPFXS(v, 1), 2)
vPFXS(v, 1) = Left(vPFXS(v, 1), Len(vPFXS(v, 1)) - 2)
End If
Next v
.Cells(2, "I").Resize(UBound(vPFXS, 1), 1) = vPFXS
.Cells(2, "L").Resize(UBound(vPFXS, 1), 1) = vSFXS
End With
End Sub
Working with variant arrays should speed up working with many cells with variable length string values. If they were all the same length then manually running a Text-to-Columns command with a fixed length to an unused column and then copying and pasting the results to the appropriate column would have done just fine.
You can get the leading numeric characters from a string using the VBA Val function. To use this function on a worksheet you will need to create a User Defined Function (UDF) in a standard VBA module.
Function LeadingNumbers(Str As String) As Double
LeadingNumbers = Val(Str)
End Function
Simply enter the function in a cell and reference the cell containing the string you want "cleaned".
Related
I create an array "Checkarray()" to collect the A column data in worksheet "Gun Log". After that I create a "For" loop function for the A column data in worksheet "Gun Inventory".
By comparing the data in two worksheets I am trying to use the Match function to locate where there is a data match, and transferring the corresponding date from one worksheet to the other.
No matter how I adjust conditions the date transfer is always "10/1/2018". I don't know where this is from.
If there are several different results matched in one worksheet, which result will the match function give at the end? In the "Gun Log" worksheet for each gun there are several matched results and I suspect that is the cause of the error.
Private Sub submitBt_Click()
Dim i As Integer
Dim c As Long
Dim g As Long
Dim CheckArray() As String
With ThisWorkbook.Sheets("Gun Log")
For c = 2 To .Cells(Rows.Count, "A").End(xlUp).Row
ReDim Preserve CheckArray(c - 1)
CheckArray(c - 1) = .Cells(c, "A").Value
Next c
End With
For g = 1 To UBound(CheckArray) Step 1
If UCase(CheckArray(g)) = UCase(.Cells(i, "A")) Then
.Cells(i, "E") = Worksheets("Gun Log").Cells(Application.Match(CheckArray(g), .Columns(1)) + 1, "B").Value
Debug.Print Application.Match(CheckArray(g), .Columns(1))
Debug.Print Worksheets("Gun Log").Cells(Application.Match(CheckArray(g), .Columns(1)) + 1, "B").Value
End If
Next g
Next i
End With
End Sub
Try to use all the arguments of Match() so that you can ensure you have an exact match.
You might be matching partially, which is why you only have one output. You used:
Worksheets("Gun Log").Cells(Application.Match(CheckArray(g), .Columns(1)) + 1, "B").Value
'AND
Application.Match(CheckArray(g), .Columns(1))
The third argument for match is if it should be an exact match, so try:
Worksheets("Gun Log").Cells(Application.Match(CheckArray(g), .Columns(1), 0) + 1, "B").Value
'AND
Application.Match(CheckArray(g), .Columns(1), 0)
That "0" I added (third argument) means you need an exact match.
I need help in solving the problem:
Formula in Excel cell is like this-> =20000-17000+1000 , I need to split the figures in different columns like this-> 20000 | 17000 | 1000 , no problem with removing + / -, I can live without them. Unable to find any help hence posted here.
Thanking in advance.example given
CTR+H and change sign - into whatever unique like # then replace + the same way into #.
After having 20000#17000#1000use:
Data/Text to columns/Delimited/Other and type #
You may record a macro to have it automated.
This Sub can do it:
Public Sub SplitSum(rngInput As Range, rngOutputStart As Range)
Dim varParts As Variant: varParts = Split(Replace(Replace(Mid(rngInput.Formula, 2), "-", "|"), "+", "|"), "|")
Dim c As Long: For c = LBound(varParts) To UBound(varParts)
rngOutputStart.offset(0, c - LBound(varParts)).Value = CDbl(varParts(c))
Next c
End Sub
You can use it like this:
SplitSum ActiveCell, ActiveCell.Offset(0, 1)
This function will preserve the sign before your numbers and has been written simply so as to permit you easy access for further tweaking if necessary.
Sub SumsToColumns(Rng As Range)
Dim RngVal As String
Dim Vals() As String
Dim n As Integer
RngVal = Trim(Rng.Cells(1).Formula)
If Len(RngVal) Then
RngVal = Mid(Replace(RngVal, "+ ", "+"), 2)
RngVal = Replace(RngVal, " +", " +")
RngVal = Replace(RngVal, "- ", "-")
RngVal = Replace(RngVal, "-", " -")
Do
n = Len(RngVal)
RngVal = Replace(RngVal, " ", " ")
Loop While Len(RngVal) < n
Vals = Split(RngVal)
For n = 0 To UBound(Vals)
With Rng
.Worksheet.Cells(.Row, .Column + n + 2).Value = Vals(n)
End With
Next n
End If
End Sub
You can call this function with a line like this:-
SumsToColumns(Range("G13"))
where "G13" is a range you might extract from a simple procedure that loops through all cells in a column. Please take note of the following line in the code.
.Worksheet.Cells(.Row, .Column + n + 2).Value
It specifies that the result should be written in the same worksheet as where the Range("G13") was taken from, in the same row (13 in this case) and starting 2 columns to the right, in this case "G" + 2 columns = "I". You can modify the "2" to any offset you might require. The result will be split over as many columns as there are separate numbers in G13.
How do I extract only the first two letters and the 6 digit number from one cell to another? ie. Column 1 will have aa111111, bb222222, ccccc, dd12, eeee1
I only want to copy aa111111 and bb222222 in this case.
Thanks,
Alex
Try this short macro:
Sub KopyKat()
Dim N As Long, i As Long, K As Long
Dim s As String
N = Cells(Rows.Count, 1).End(xlUp).Row
K = 1
For i = 1 To N
s = Cells(i, 1).Value
If Len(s) = 8 _
And Mid(s, 1, 1) Like "[a-zA-Z]" _
And Mid(s, 2, 1) Like "[a-zA-Z]" _
And IsNumeric(Mid(s, 3)) Then
Cells(K, 2).Value = s
K = K + 1
End If
Next i
End Sub
If your strings are in A:A then in B1 (and copy down):
=IF(LEN(A1)>7,IF(AND(CODE(LOWER(MID(A1,{1,2},1)))<>CODE(UPPER(MID(A1,{1,2},1))),ISNUMBER(MID(A1,{3;4;5;6;7;8},1)*1)),LEFT(A1,8),""),"")
This is an array formula and must be confirmed with ctrl + shift + enter.
Running evaluate formula shows what happens and how it works :)
Using VBA then this will do:
Sub CopyMe()
Dim x As Variant, i As Long
For Each x In Range([A1], Cells(Rows.Count, 1).End(xlUp)).Value2
If x Like "[a-zA-Z][a-zA-Z]######" Then
i = i + 1
Cells(i, 2) = x
End If
Next
End Sub
Here is another way to do it. The formula loops through your string looking for a 6 digit number, at which point it takes the previous two characters (as long as they exist) and returns the 8 character string. Otherwise it returns an empty string.
=IFERROR(MID(A1,SUMPRODUCT(ROW($A$1:$A$100),--ISNUMBER(VALUE(MID(A1,ROW($A$1:$A$100),6))))-2,8),"")
Loops 100 times, so will work with strings up to a maximum length of 106 characters. To use the formula place your string in column A, and place this formula in cell B1 (for example) and drag down
I have a columns of strings as follows. How can I put the symbol '<' in between the characters ?
'ABCDE'
'BCG'
'ABCD'
The expected output should be:
A<B<C<D<E
B<C<G
A<B<C<D
=concatenate(left(A1,1),"<",mid(A1,2,1),"<",mid(A1,3,1),(if(len(A1)>3,"<"&mid(A1,4,1)&if(len(A1)>4,"<"&mid(A1,5,1),""),"")))
Will do what you want for values up to 5 letters, and as few as 3 letters. Otherwise you can change it.
Basically it adds a "<" between the first 3 letters and then checks whether the string is longer than 3 letters and if so, adds more "<" characters. If this needs to be more dynamic it's far easier in vba.
A manual, one-off, no-VBA approach would be:
use the Text to Columns tool with Fixed Width and place the markers after each character.
then use a formula like this to append values and separator
The formula could look like this if your values are in row 1
=A1&IF(LEN(B1)>0,">"&B1,"")&IF(LEN(C1)>0,">"&C1,"")&IF(LEN(D1)>0,">"&D1,"")&IF(LEN(E1)>0,">"&E1,"")
Adjust formula to suit the maximum number of characters in a cell.
Such things are not for formulas...
As you tag question as Excel-VBA too, so:
'''''''
Private Sub sb_Test_fp_AddSym()
Debug.Print fp_AddSym("abncd", "<")
End Sub
Public Function fp_AddSym(pStr$, pSym$) As String
Dim i&, j&, iLB&, iUBs&, iUBt&
Dim tSrc() As Byte, tTgt() As Byte, tSym As Byte
tSrc = pStr
tSym = Asc(pSym)
iLB = LBound(tSrc)
iUBs = UBound(tSrc)
iUBt = iUBs * 2 + 3
ReDim tTgt(iLB To iUBt)
For i = iLB To iUBs Step 2
j = i * 2
tTgt(j) = tSrc(i)
tTgt(j + 1) = tSrc(i + 1)
tTgt(j + 2) = tSym
tTgt(j + 3) = 0
Next
ReDim Preserve tTgt(iLB To (iUBt - 4))
Debug.Print tTgt
Stop
fp_AddSym = tTgt
End Function
'''
This worked for me:
Sub SymbolInsert()
Dim cl As Range, temp As String
For Each cl In Range("A1:A3") '~~~> Define your range here
For i = 1 To Len(cl)
temp = temp & Mid(cl, i, 1) & "<"
Next i
cl = IIf(VBA.Right$(temp, 1) = "<", VBA.Left$(temp, Len(temp) - 1), temp)
temp = vbNullString
Next cl
End Sub
It can probably be done with Excel formula for any length, but here is the shortest VBA solution
For Each c In Range("A:A").SpecialCells(xlCellTypeConstants)
c.Value2 = Replace( Left$( StrConv( c, vbUnicode), Len(c) * 2 - 1), vbNullChar, "<")
Next
I am hoping someone could help me out with a VBA Excel macro.
I have received a worksheet in Excel 2007 which contains product names in one column, and I need to sort this into a logical format so I can use it. However, the list itself is not in any kind of logical order, is 10 000 rows long and I am going to have to do this every month!!
Basically, what I would like to do is search for certain keywords which are common to most of the entries and move them into separate cells in different columns (but in the same row as the original entry).
Regarding keywords: There are 3 different types, two of which I have a complete list of.
Example of keywords: some are measures such as cm (centimetre), mm (millimetre), m (metre) etc.). Then there are other keywords such as % and finally a last set of keywords which is wood, plastic, glass etc.
If this was not complicated enough, the measures (cm for example) are duplicated in some instances and are important details so I cant just separate them but would ideally like them in two adjacent cells.
Fortunately, there is a space after each measure, % sign and item material.
Working from right to left is the easiest way I can think of achieving this as the first description in the string varies wildly between entries and that can stay as is.
So, below is an example string, lets say this is in Cell A1. (Inverted commas are not included in the string and the word "by" appears in only about 100 cases. Usually it is missing...)
"Chair Leg Wood 100% 1m by 20cm"
I would ideally like for the string to be split up into cells as follows
Cell B1 - Chair Leg
Cell C1 - Wood
Cell D1 - 1m
Cell E1 - 2cm
Cell F1 - 100%
Having the % measures in the same column would be extremely helpful
Can anyone please help me with this or the beginnings of a macro which does this and then moves down the list - I have tried using some basic "find" and "len" formulas but really am at my wits end on how to deal with this!
The task boils down to defining a robust definition of the structure of the input data.
Form the info provided a candidate definition might be
<Description, one or more words> <Material, one word> <A value followd by %> <Dimension A> <optional "by"> <Dimension B>
The following macro will process data that conforms this this spec. The definition may need
expanding, eg two word materials (eg Mild Steel)
You will need to add error handling in case any rows don't conform, eg no % in the string, or % character elsewhere in string
Option Explicit
Dim dat As Variant
Sub ProcessData()
Dim r As Range
Dim i As Long
Set r = Intersect(ActiveSheet.UsedRange, ActiveSheet.Columns(1)).Resize(, 5)
dat = r
For i = 1 To UBound(dat, 1)
ParseRow i, CStr(dat(i, 1))
Next
r = dat
ActiveSheet.Columns(5).Style = "Percent"
End Sub
Sub ParseRow(rw As Long, s As String)
'Chair Leg Wood 100% 1m by 20cm
Dim i As Long
Dim sDim As String, sPCnt As String, sMat As String, sDesc As String
Dim sA As String, sB As String
i = InStr(s, "% ")
sDim = Trim(Replace(Mid(s, i + 2), " by ", " ")) ' text to right of %, remove "by"
sA = Trim(Left(sDim, InStr(sDim, " "))) ' split dimension string in two
sB = Trim(Mid(sDim, InStr(sDim, " ")))
s = Left(s, i)
i = InStrRev(s, " ")
sPCnt = Mid(s, i + 1) ' text back to first space before %
s = Trim(Left(s, i))
i = InStrRev(s, " ") ' last word in string
sMat = Mid(s, i + 1)
sDesc = Trim(Left(s, i)) ' whats left
dat(rw, 1) = sDesc
dat(rw, 2) = sMat
dat(rw, 3) = sA
dat(rw, 4) = sB
dat(rw, 5) = sPCnt
End Sub
First, I'd use the Split function to separate the parts into an array, this will avoid most of the string functions and string math:
Dim parts As Variant
parts = Split(A1)
Then, I'd do my comparisons to each part.
Finally, I'd concatenate the parts I didn't breakout, and place all parts on the sheet.
This is based on your example which has spaces inbetween every part, though something similar could work otherwise, you just have to do more work with each part.
Here's my stab at it. We could use about 10 more examples, but this should be a start. To use, select a one column range with your descriptions and run SplitProduct. It will split it out to the right of each cell.
Sub SplitProducts()
Dim rCell As Range
Dim vaSplit As Variant
Dim i As Long
Dim aOutput() As Variant
Dim lCnt As Long
Const lCOLDESC As Long = 1
Const lCOLMAT As Long = 2
Const lCOLPCT As Long = 3
Const lCOLREM As Long = 4
If TypeName(Selection) = "Range" Then
If Selection.Columns.Count = 1 Then
For Each rCell In Selection.Cells
'split into words
vaSplit = Split(rCell.Value, Space(1))
ReDim aOutput(1 To 1, 1 To 1)
'loop through the words
For i = LBound(vaSplit) To UBound(vaSplit)
Select Case True
Case IsPercent(vaSplit(i))
'percents always go in the same column
lCnt = lCOLPCT
If UBound(aOutput, 2) < lCnt Then
ReDim Preserve aOutput(1 To 1, 1 To lCnt)
End If
aOutput(1, lCnt) = vaSplit(i)
Case IsInList(vaSplit(i))
'list items always go in the same column
lCnt = lCOLMAT
ReDim Preserve aOutput(1 To 1, 1 To lCnt)
If UBound(aOutput, 2) < lCnt Then
ReDim Preserve aOutput(1 To 1, 1 To lCnt)
End If
aOutput(1, lCnt) = vaSplit(i)
Case IsMeasure(vaSplit(i))
'measurements go in the last column(s)
If UBound(aOutput, 2) < lCOLREM Then
lCnt = lCOLREM
Else
lCnt = UBound(aOutput, 2) + 1
End If
ReDim Preserve aOutput(1 To 1, 1 To lCnt)
aOutput(1, lCnt) = vaSplit(i)
Case Else
'everything else gets concatentated in the desc column
aOutput(1, lCOLDESC) = aOutput(1, lCOLDESC) & " " & vaSplit(i)
End Select
Next i
'remove any extraneous spaces
aOutput(1, lCOLDESC) = Trim(aOutput(1, lCOLDESC))
'write the values to the left of the input range
rCell.Offset(0, 1).Resize(1, UBound(aOutput, 2)).Value = aOutput
Next rCell
Else
MsgBox "Select a one column range"
End If
End If
End Sub
Function IsPercent(ByVal sInput As String) As Boolean
IsPercent = Right$(sInput, 1) = "%"
End Function
Function IsInList(ByVal sInput As String) As Boolean
Dim vaList As Variant
Dim vaTest As Variant
'add list items as needed
vaList = Array("Wood", "Glass", "Plastic")
vaTest = Filter(vaList, sInput)
IsInList = UBound(vaTest) > -1
End Function
Function IsMeasure(ByVal sInput As String) As Boolean
Dim vaMeas As Variant
Dim i As Long
'add measurements as needed
vaMeas = Array("mm", "cm", "m")
For i = LBound(vaMeas) To UBound(vaMeas)
'any number of characters that end in a number and a measurement
If sInput Like "*#" & vaMeas(i) Then
IsMeasure = True
Exit For
End If
Next i
End Function
No guarantees that this will be speedy on 10k rows.