VBA find select all then shift all adjacent cells to the right - vba

I'm trying to write a macro that will sort a work book that is generated by a system at work. I have attempted to chopshop some code together from other posts on this site with no success.
The goal is to search column A for any cells that contain either "IN" or "OUT" then move every thing to the right of these cells one cell to the right.
I have some code that works for the first output but it will only ever ready the first out put I know why it doesn't work but I don't know how to fix it.
Any help would be much appreciated,
Thanks,
Sub Data_only()
'
' Reworks_Data_only Macro
'
' Keyboard Shortcut: Ctrl+k
'
Columns("J:AB").Select
Selection.ClearContents
Cells.Select
Cells.EntireColumn.AutoFit`enter code here`
' ^ Cuts out unused columns and autofits the rest
Columns("A:A").Select
Selection.Find(What:="in", After:=ActiveCell, LookIn:=xlFormulas, LookAt _
:=xlWhole, SearchOrder:=xlByRows, SearchDirection:=xlNext, MatchCase:= _
False, SearchFormat:=False).Activate
' ^Searches Column A for "IN"
ActiveCell.Offset(, 1).Select
Selection.Insert Shift:=xlToRight, CopyOrigin:=xlFormatFromLeftOrAbove
' ^Selects the found cell and shift the whole row to the right
End Sub
EDIT
This is a mock up of the file im looking to change, there would normally be a few hundred batches and a lot more columns but it should be workable.
batches mock up

Something like that would be possible if you like to use the Find function ...
Option Explicit
Public Sub Data_only()
MoveByFind "IN"
MoveByFind "OUT"
End Sub
Public Function MoveByFind(FindString As String)
Dim Found As Range
Set Found = Columns("A:A").Find(What:=FindString, LookIn:=xlFormulas, LookAt:=xlWhole, _
SearchOrder:=xlByRows, SearchDirection:=xlNext, MatchCase:=False, SearchFormat:=False)
If Not Found Is Nothing Then
Dim firstAddress As String
firstAddress = Found.Address 'remember first find for no endless loop
Do
Found.Offset(0, 1).Insert Shift:=xlToRight 'move cells right
Set Found = Columns("A:A").FindNext(After:=Found) 'find next
Loop While Not Found Is Nothing And Found.Address <> firstAddress 'loop until end or nothing found
End If
End Function

You can do this with a simple loop, rather than using the Find function:
Dim i as Long, LR as Long
LR = Cells(Rows.Count,1).End(xlUp).Row
For i = 2 to LR 'Assumes you have a header in row 1
If Cells(i,1).Value = "IN" OR Cells(i,1).Value = "OUT" Then
Cells(i,2).Insert Shift:=xlToRight
End If
Next i
Note that In and Out are case-sensitive.
You could also do this with the Find function, though you would find all, or use find next, and use the .insert as you've doen in your code.
Edit:
Assuming that the issue is hidden characters, InStr can be used:
Dim i As Long, LR As Long, j As Integer, k As Integer
LR = Cells(Rows.Count, 1).End(xlUp).Row
For i = 2 To LR 'Assumes you have a header in row 1
j = InStr(Cells(i, 1).Value, "IN")
k = InStr(Cells(i, 1).Value, "OUT")
If j > 0 Or k > 0 Then
Cells(i, 2).Insert Shift:=xlToRight
End If
Next i

Related

VBA-Excel CTRL Find

I am currently trying to find a certain word within an excel spreadsheet, copy the cell on the right and then paste it a further 3 cells to the right and 3 cells down, before dragging this down.
I have compiled the following which does the job.
Cells.Find(What:="N/C:", After:=ActiveCell, LookIn:=xlFormulas, LookAt _
:=xlPart, SearchOrder:=xlByRows, SearchDirection:=xlNext, MatchCase:= _
False, SearchFormat:=False).Activate
Selection.Offset(0, 1).Select
Selection.Copy
Selection.Offset(3, 3).Select
ActiveSheet.Paste
Range(Selection, Selection.End(xlDown)).Select
Selection.FillDown
My question is:
How can I extend this code so it searches for all "N/C:" and does the above
Feel free to provide updates to my initial code if it can be improved
Lightly tested:
Sub Tester()
Dim col As Collection, c, sht As Worksheet
Set sht = ActiveSheet
Set col = FindAll(sht.UsedRange, "N/C:")
Debug.Print "Found " & col.Count & " matches"
For Each c In col
c.Copy c.Offset(3, 3)
sht.Range(c.Offset(3, 3), c.Offset(3, 3).End(xlDown)).FillDown
Next c
End Sub
Public Function FindAll(rng As Range, val As String) As Collection
Dim rv As New Collection, f As Range
Dim addr As String
Set f = rng.Find(what:=val, after:=rng.Cells(rng.Cells.Count), _
LookIn:=xlValues, LookAt:=xlPart, SearchOrder:=xlByRows, _
SearchDirection:=xlNext, MatchCase:=False)
If Not f Is Nothing Then addr = f.Address()
Do Until f Is Nothing
rv.Add f
Set f = rng.FindNext(after:=f)
If f.Address() = addr Then Exit Do
Loop
Set FindAll = rv
End Function
The short answer is that there is no built-in way to return a range with all the find results (i.e. find all) in one go. You have to find the first result (the code you already have) and then use findNext within a while loop, exiting only when the next result until it refers to the same cell as the first result.
There is a good explanation/implementation at http://www.cpearson.com/excel/findall.aspx

Excel VBA - How to select the whole table of borders

i am very new to Excel VB. I am hoping you can assist with my problem.
I have several tables like this
The tables can be edited such as by inserting new rows, etc by the user.
I want to highlight and copy the latest table (the one at the very last row) and paste it at the next available space, 3 rows down.
I managed to do this, but I can only highlight and copy the cells with data. So should there be an empty row in the middle of the table, or an empty last row with borders, it would not copy correctly, as shown here:
I do still need to copy everything within the borders including empty rows, but I lack the skills and knowledge to do so. I hope you can assist.
The following is my code:
Sub CopyPaste()
LastRow = Cells.Find("*", SearchOrder:=xlByRows, SearchDirection:=xlPrevious).Row
FirstColumn = Cells.Find("*", SearchOrder:=xlByRows, SearchDirection:=xlNext).Column
LastColumn = Cells.Find("*", SearchOrder:=xlByColumns, SearchDirection:=xlPrevious).Column
BelowLastName = Cells.Find("", After:=Cells(LastRow, FirstColumn), SearchOrder:=xlByColumns, SearchDirection:=xlPrevious).Row
Cells(BelowLastName, FirstColumn).Select 'This selects C5 (refer image)
Selection.Offset(-1).Select 'This selects C4 (refer image)
Range(Selection, Cells(LastRow, LastColumn)).Select 'This highlights whole table
Selection.Copy
Cells(LastRow, FirstColumn).Select
ActiveCell.Offset(3).Select
ActiveSheet.Paste
Application.CutCopyMode = False
End Sub
Try this
Sub x()
Dim rEnd As Range, rStart As Range, i As Long
Set rEnd = Range("C" & Rows.Count).End(xlUp)
Do While rEnd.Offset(i).Borders(xlEdgeBottom).LineStyle = xlContinuous
i = i - 1
Loop
Set rStart = rEnd.Offset(i + 1)
Range(rStart, rEnd).Resize(, 8).Copy rEnd.Offset(3)
End Sub

Search again if not found

So I have a part in my macro that I want to add what I assume needs to be an "Else" portion, but I am not that good with macros and am asking for help.
Range("Z1").Copy
Dim FindString As String
Dim Rng As Range
FindString = Sheets("Pull").Range("Y1").Value
If Trim(FindString) <> "" Then
With Sheets("HourTracker").Range("A:A")
Set Rng = .Find(What:=FindString, _
After:=.Cells(.Cells.Count), _
LookIn:=xlValues, _
LookAt:=xlWhole, _
SearchOrder:=xlByRows, _
SearchDirection:=xlNext, _
MatchCase:=False)
If Not Rng Is Nothing Then
Application.Goto Rng, True
Else
MsgBox "Nothing found"
End If
End With
ActiveCell.Offset(0, 1).Activate
Selection.PasteSpecial xlPasteValues
Application.DisplayAlerts = True
End If
End Sub
So what I want this to do, is instead of "MsgBox "Nothing Found"", I want it to essentially perform the same thing as above, but copy cell Z2, and search for the value of Y2 in the same sheet "HourTracker" then paste the value. I have no idea on how to accomplish this, and all my attempts have failed. Any help would be much appreciated. Let me know if you need more clarification, thank you in advance!!!
Sounds to me like you're looking for a loop.
Sub findStuff()
Application.DisplayAlerts = False
' The item you want to paste
Dim PasteString As String
' The item you're looking for
Dim FindString As String
' The range that may containing FindString
Dim Rng As Range
' The variable used to loop through your range
Dim iCounter as Long
' loop through the first cell in column Y to the last used cell
For iCounter = 1 To Sheets("Pull").Cells(Rows.Count, 25).End(xlUp).Row
' PasteString = the current cell in column Z
PasteString = Sheets("Pull").Cells(iCounter, 26).Value
' FindString = the current cell in column Y
FindString = Sheets("Pull").Cells(iCounter, 25).Value
If Trim(FindString) <> "" Then
With Sheets("HourTracker").Range("A:A")
' Find the cell containing FindString
Set Rng = .Find(What:=FindString, _
After:=.Cells(.Cells.Count), _
LookIn:=xlValues, _
LookAt:=xlWhole, _
SearchOrder:=xlByRows, _
SearchDirection:=xlNext, _
MatchCase:=False)
If Not Rng Is Nothing Then
' There's no need to activate/ select the cell.
' You can directly set the value with .Value
Rng.Offset(0, 1).Value = PasteString
Else
' Do nothing
End If
End With
Else
' Do nothing
End If
Next
Application.DisplayAlerts = True
End Sub
Every time the compiler hits Next it will start again at For but raise the value of iCounter by 1. We can use Cells to accomplish this since Cells takes the row and column arguments as numbers, not strings (like Range). The syntax is simply Cells(Row #, Column #). Therefore, every time the For . . . Next loops around again, iCounter will go up by one and you'll search in the next row.
Instead of using .Paste, you can set the value of a cell directly with .Value. Pasting is pretty slow and using .Value is much faster.
Cells().End(xlUp).Row is a method used to find the last used cell in a range. See Error in finding last used cell in VBA for a much better explanation than I can give here.

VBA for searching string in a column and copy entire rows depending on the presence of certain string at adjacent cell

I am completely new for VBA.
I have excel data sheet containing numbers and strings. I want to search for certain string say 'CYP' in column I then look for a cell of its row at column C and copy entire rows containing the string of cell C. I want to paste in sheet 2 of the same workbook and loop it again to look for remaining CYPs in column.
Would you help me on this please?
After the suggestion from pnuts, here is my macro code
Sub Macro1()
'
' Macro1 Macro
'
'
Columns("I:I").Select
Range("I729").Activate
Selection.Find(What:="cyp", After:=ActiveCell, LookIn:=xlValues, LookAt _
:=xlPart, SearchOrder:=xlByRows, SearchDirection:=xlNext, MatchCase:= _
False, SearchFormat:=False).Activate
ActiveWindow.SmallScroll Down:=5
Range("C749").Select
Selection.Copy
Columns("C:C").Select
Range("C734").Activate
Selection.Find(What:="EPT001TT0601C000151", After:=ActiveCell, LookIn:= _
xlValues, LookAt:=xlPart, SearchOrder:=xlByRows, SearchDirection:=xlNext _
, MatchCase:=False, SearchFormat:=False).Activate
Rows("746:750").Select
Application.CutCopyMode = False
Selection.Copy
Sheets("Sheet2").Select
ActiveSheet.Paste
End Sub
In this code the CYP was found in I749, cell C749 was copied as string and first row in column C containing the same string was searched followed by copying of the entire row and 4 more followed by it then pasting in sheet2 of the same workbook.
What I wanted was to loop this action again and again upto the end of column I and repeat the same action.
Thank you!
I managed to solve the problem with the help of Trebor76 at Excelforum. Here I am giving solution in that way it might be helpful for some newbies like myself with similar problem.
Option Explicit
Sub Macro1()
'Written and assisted by Trebor76
'Copy an entire row from Sheet1 to Sheet2 for each unique matching item in Col. C if the text in Col. I contains the text 'CYP' (case sensitive)
'http://www.excelforum.com/excel-programming-vba-macros/962511-vba-for-searching-string-in-a-column-and-copy-rows-depending-on-string-in-adjacent-cell.html
Dim rngCell As Range
Dim objMyUniqueArray As Object
Dim lngMyArrayCounter As Long
Dim lngMyRow As Long
Dim varMyItem As Variant
Application.ScreenUpdating = False
Set objMyUniqueArray = CreateObject("Scripting.Dictionary")
For Each rngCell In Sheets("Sheet1").Range("I1:I" & Sheets("Sheet1").Range("I" & Rows.Count).End(xlUp).Row)
If InStr(rngCell, "CYP") > 0 Then
If Not objMyUniqueArray.Exists(Trim(Cells(rngCell.Row, "C"))) Then
lngMyArrayCounter = lngMyArrayCounter + 1
objMyUniqueArray.Add (Trim(Cells(rngCell.Row, "C"))), lngMyArrayCounter
varMyItem = Sheets("Sheet1").Cells(rngCell.Row, "C")
For lngMyRow = 1 To Sheets("Sheet1").Cells(Rows.Count, "C").End(xlUp).Row
If Sheets("Sheet1").Cells(lngMyRow, "C") = varMyItem Then
Rows(lngMyRow).Copy Destination:=Sheets("Sheet2").Range("A" & Sheets("Sheet2").Range("A" & Rows.Count).End(xlUp).Row + 1)
End If
Next lngMyRow
End If
End If
Next rngCell
Set objMyUniqueArray = Nothing
Application.ScreenUpdating = True
MsgBox "All applicable rows have been copied.", vbInformation
End Sub
Cheers!

VBA - Problems dynamically selecting a range

I am new to VBA and am trying to write a macro that takes a workbook with several sheets of data and formats it for printing. Each sheet has tables of information (like operating/income statements). I want this code to be able to work for workbooks anyone creates but has the same basic information. This means I need to find start and end of the data on each sheet because it is not always in the same place (someone might start from "A1" and someone else from "B4", etc).
I've looked on the many websites for different ways to locate the first row used and last column used. What I have so far sometimes locates the starting row, ending row, starting column, and ending column correctly and other times it doesn't.
Sub FormatWorkbook()
Dim ws As Worksheet
Dim rowStart As Long
Dim columnStart As Long
Dim rowEnd As Long
Dim columnEnd As Long
Dim printStart As String
Dim printEnd As String
Application.ScreenUpdating = False
'Turn off print communication
Application.PrintCommunication = False
'Loop through sheets
For Each ws In Worksheets
'Make current sheet activesheet
ws.Select
'Set rowStart, columnStart, rowEnd, and columnEnd to the used range
With ActiveSheet
rowStart = .Cells.Find(what:="*", after:=.Range("A1"), LookAt:=xlPart, LookIn:=xlFormulas, searchorder:=xlByRows, searchdirection:=xlNext, MatchCase:=False).Row
columnStart = .Cells.Find(what:="*", after:=.Range("A1"), LookAt:=xlPart, LookIn:=xlFormulas, searchorder:=xlByColumns, searchdirection:=xlNext, MatchCase:=False).Column
rowEnd = .Cells.Find(what:="*", after:=.Range("A1"), LookAt:=xlPart, LookIn:=xlFormulas, searchorder:=xlByRows, searchdirection:=xlPrevious, MatchCase:=False).Row
columnEnd = .Cells.Find(what:="*", after:=.Range("A1"), LookAt:=xlPart, LookIn:=xlValues, searchorder:=xlByColumns, searchdirection:=xlPrevious, MatchCase:=False).Column
End With
This is just a portion of the program but the one I am most confused about. If anyone could help out I would really appreciate it. Also, if there is a better way to accomplish this task I'm all ears. The rest of my code is below for reference.
'Insert or Delete Space above the first used row
If rowStart < 4 Then
Do While rowStart < 4
Range("1:1").Select
Selection.Insert Shift:=xlDown, CopyOrigin:=xlFormatFromLeftOrAbove
ws.Select
With ActiveSheet
rowStart = .Cells.Find(what:="*", after:=.Range("A1"), LookIn:=xlValues, searchorder:=xlByRows, searchdirection:=xlNext).Row
End With
Loop
ElseIf rowStart > 4 Then
Do While rowStart > 4
Range("1:1").Select
Selection.Delete Shift:=xlUp
ws.Select
With ActiveSheet
rowStart = .Cells.Find(what:="*", after:=.Range("A1"), LookIn:=xlValues, searchorder:=xlByRows, searchdirection:=xlNext).Row
End With
Loop
End If
'I think I need to adjust the columnStart, rowEnd, and columnEnd values after inserting and deleting rows
ws.Select
printStart = ActiveSheet.Cells(1, columnStart).Address
printEnd = ActiveSheet.Cells(rowEnd, columnEnd).Address
'Format headers, footers, and set the print area
ActiveSheet.PageSetup.CenterHeaderPicture.Filename = _
"\\antilles\MyDocs\xxxx\My Documents\My Pictures\xxxx.png"
With ActiveSheet.PageSetup
.CenterHeader = "&G"
.LeftFooter = "&""Palatino Linotype,Regular""&F"
.CenterFooter = "&""Palatino Linotype,Regular""Prepared By: xxxx"
.RightFooter = "&""Palatino Linotype,Regular""&D"
.PrintArea = printStart & ":" & printEnd
End With
Next ws
Application.PrintCommunication = True
End Sub
I've done a lot of this and I recommend simple crude methods. Without coding a whole thing, but rather hinting...
dim iRow as integer
For iRow = 1 to ...
cells(iRow,65000).end(xlup).select
if activecell.row = 1 then
activecell.entirecolumn.delete
exit For
endif
next iRow
As much as possible force some structure on the sheets. Then go see
http://www.ozgrid.com/VBA/ExcelRanges.htm
When googling, include
ozgrid|Pearson|Tushar|"Mr. Excel"|Erlandsen|Peltier|dailydoseofexcel
in the search string.
Excel VBA offers a selection of techniques for finding the first or last used row or column but none work in every situation.
Some problems with your code:
If the worksheet contains something, Find returns a range. A range has a row so your statements will work. But if the worksheet is empty, Find returns Nothing. You must use Set Rng = .Cells.Find ... then test Rng to not be Nothing before accessing Rng.Row or Rng.Column. See the code I reference below if this is not clear.
Note the after in After:=.Range("A1"). Find does not examine .Range("A1") until it has searched every other cell and wraps back to the beginning. In any example in which the start point is .Range("A1") the search direction will be xlPrevious so it immediately wraps and starts searching from the bottom right cell. Try After:=.Cells(Rows.Count, Columns.Count) when the search direction is xlNext.
There was an earlier question that was similar to yours. I posted some code which showed a selection of techniques for finding the last row or column and the situations in which they fail. I suggest you visit that answer and try the code: https://stackoverflow.com/a/18220846/973283.
Good luck and happy VBA programming.