I have this problem I can't seem to fix...
In column L I have certain roles, these roles are divided by || (pipes).
The problem: Some people deliver these roles they want to use like this:
Testing||Admin||Moderator||
But this doesn't work for the script we use to import these roles, what I would like to see is that whenever || (pipes) are used and after the pipes are used if there isn't any text following it up it should delete the pipes at the end.
What I tried is the find and replace option, but this also removes the pipes in between the text.
Hope someone can help me!
Problem:
Testing||Admin||Moderator||
Solution:
Testing||Admin||Moderator
A simple formula can solve your requirements
=IF(RIGHT(TRIM(A1),2)="||",LEFT(TRIM(A1),LEN(TRIM(A1))-2),A1)
The above formula is based on the below logic.
Check if the right 2 characters are ||
If "Yes", then take the left characters (LEN - 2)
If "No", then return the string as it is.
If you still want VBA then try this code which will make the change in the entire column in one go. Explanation about this method is given HERE.
For demonstration purpose, I am assuming that the data is in column A of Sheet1. Change as applicable.
Option Explicit
Sub Sample()
Dim ws As Worksheet
Dim lrow As Long
Dim rng As Range
Dim sAddr As String
Set ws = Sheet1
With ws
lrow = .Range("A" & .Rows.Count).End(xlUp).Row
Set rng = .Range("A1:A" & lrow)
sAddr = rng.Address
rng = Evaluate("index(IF(RIGHT(TRIM(" & sAddr & _
"),2)=""||"",LEFT(TRIM(" & sAddr & _
"),LEN(TRIM(" & sAddr & _
"))-2)," & sAddr & _
"),)")
End With
End Sub
In Action:
I only changed the name of the worksheet and the range to L and L2:L. – Ulquiorra Schiffer 17 mins ago
There are different ways of doing this, but here is one:
Function FixPipes(val As String) As String
Dim v As Variant
v = Split(val, "||")
If Len(v(UBound(v))) > 0 Then
FixPipes = val
Else
FixPipes = Mid$(val, 1, Len(val) - 2)
End If
End Function
Here's another way to do it:
Function FixPipes(val As String) As String
If Mid$(val, Len(val) - 1, 2) <> "||" Then
FixPipes = val
Else
FixPipes = Mid$(val, 1, Len(val) - 2)
End If
End Function
Usage:
Sub test()
Debug.Print FixPipes("Testing||Admin||Moderator||")
End Sub
Or:
Sub LoopIt()
' remove this line after verifying the sheet name
MsgBox ActiveSheet.Name
Dim lIndex As Long
Dim lastRow As Long
lastRow = Range("L" & Rows.Count).End(xlUp).Row
For lIndex = 1 To lastRow
Range("L" & lIndex) = FixPipes(Range("L" & lIndex))
Next
End Sub
https://learn.microsoft.com/en-us/office/vba/language/reference/user-interface-help/split-function
https://learn.microsoft.com/en-us/office/vba/language/reference/user-interface-help/mid-function
A tiny alternative using negative filtering would be:
Function FixPipes(ByVal s As String, Optional delim As String = "||") As String
Dim tmp: tmp = Filter(Split(s & "$$", delim), "$$", False)
FixPipes = Replace(Join(tmp, delim), "$$", "")
End Function
=IF(UNICODE(RIGHT(A2,1))+UNICODE(LEFT(RIGHT(A2,2),1))=248,LEFT(A2,LEN(A2)-2),A2)
Solution using the Replace formula, if you want to do this in VBA you can use the replace function in VBA as well
Remove Trailing String
All Except OP
This is a follow-up question on How to create data validation based on multiple roles?
.
The answers from Siddharth Rout and braX are valid for someone who might stumble upon this post.
They would have to be adjusted for OP because this case is 'clouded' by an already existing Worksheet_Change event.
OP (Ulquiorra)
To not complicate I have integrated a code snippet, which uses a function (similar to the posted solutions), into your existing code and removed Areas since it seems redundant after seeing what you are trying to accomplish.
The Snippet
Application.ScreenUpdating = False
Application.EnableEvents = False
Dim cel As Range
For Each cel In rng.Cells
cel.Value = removeTrail(cel.Value, Delimiter)
Next cel
Application.EnableEvents = True
The Function
Function removeTrail( _
ByVal SearchString As String, _
ByVal RemoveString As String, _
Optional ByVal doTrim As Boolean = True) _
As String
If doTrim Then
removeTrail = Trim(SearchString)
Else
removeTrail = SearchString
End If
If Right(removeTrail, Len(RemoveString)) = RemoveString Then
removeTrail = Left(removeTrail, Len(removeTrail) - Len(RemoveString))
End If
End Function
The Worksheet Change (modified)
Option Explicit
Private Sub Worksheet_Change(ByVal Target As Range)
Const RolesList As String = "Admin,Clerk,Moderator,User"
Const FirstCellAddress As String = "L2"
Const Delimiter As String = "||"
Dim rng As Range
With Range(FirstCellAddress)
Set rng = Intersect(.Resize(.Worksheet.Rows.Count - .Row + 1), Target)
End With
If rng Is Nothing Then
Exit Sub
End If
' The Snippet
Application.ScreenUpdating = False
Application.EnableEvents = False
Dim cel As Range
For Each cel In rng.Cells
cel.Value = removeTrail(cel.Value, Delimiter)
Next cel
Application.EnableEvents = True
Dim Roles() As String: Roles = Split(RolesList, ",")
Dim dRng As Range
Dim aRng As Range
Dim Curr() As String
Dim cMatch As Variant
Dim n As Long
Dim isFound As Boolean
For Each cel In rng.Cells
If Not IsError(cel) Then
Curr = Split(cel.Value, Delimiter)
For n = 0 To UBound(Curr)
cMatch = Application.Match(Curr(n), Roles, 0)
If IsError(cMatch) Then
isFound = True
Exit For
Else
' Remove this block if you don't need case-sensitivity.
If StrComp(Curr(n), Roles(cMatch - 1), _
vbBinaryCompare) <> 0 Then
isFound = True
Exit For
End If
End If
Next n
If isFound Then
isFound = False
If dRng Is Nothing Then
Set dRng = cel
Else
Set dRng = Union(dRng, cel)
End If
End If
End If
Next cel
rng.Interior.Color = xlNone
If Not dRng Is Nothing Then
dRng.Interior.Color = vbRed
End If
Application.ScreenUpdating = True
End Sub
This is the piece of code I have in the worksheet change event (also module1) and also in the same active worksheet as module2:
Option Explicit
Private Sub Worksheet_Change(ByVal Target As Range)
Const RolesList As String = "Testing"
Const FirstCellAddress As String = "L2"
Const Delimiter As String = "||"
Dim rng As Range
With Range(FirstCellAddress)
Set rng = Intersect(.Resize(.Worksheet.rows.Count - .Row + 1), Target)
End With
If rng Is Nothing Then
Exit Sub
End If
Dim Roles() As String: Roles = Split(RolesList, ",")
Dim dRng As Range
Dim aRng As Range
Dim cel As Range
Dim Curr() As String
Dim cMatch As Variant
Dim n As Long
Dim isFound As Boolean
For Each aRng In rng.Areas
For Each cel In aRng.Cells
If Not IsError(cel) Then
Curr = Split(cel.Value, Delimiter)
For n = 0 To UBound(Curr)
cMatch = Application.Match(Curr(n), Roles, 0)
If IsError(cMatch) Then
isFound = True
Exit For
Else
If StrComp(Curr(n), Roles(cMatch - 1), _
vbBinaryCompare) <> 0 Then
isFound = True
Exit For
End If
End If
Next n
If isFound Then
isFound = False
If dRng Is Nothing Then
Set dRng = cel
Else
Set dRng = Union(dRng, cel)
End If
End If
End If
Next cel
Next aRng
Application.ScreenUpdating = False
rng.Interior.Color = xlNone
If Not dRng Is Nothing Then
dRng.Interior.Color = vbRed
End If
Application.ScreenUpdating = True
End Sub
I did put your code inside a module2 and also in an active worksheet:
Option Explicit
Sub Sample()
Dim ws As Worksheet
Dim lrow As Long
Dim rng As Range
Dim sAddr As String
Set ws = Sheet1
With ws
lrow = .Range("L" & .Rows.Count).End(xlUp).Row
Set rng = .Range("L2:L" & lrow)
sAddr = rng.Address
rng = Evaluate("index(IF(RIGHT(TRIM(" & sAddr & _
"),2)=""||"",LEFT(TRIM(" & sAddr & _
"),LEN(TRIM(" & sAddr & _
"))-2)," & sAddr & _
"),)")
End With
End Sub
For some reason, module2 won't work I suspect module1 to interfere with it indeed but can't find a solution.
My whole code looks like this:
Sub AllInOne()
Application.EnableEvents = True
Application.ScreenUpdating = False
Application.Calculation = xlCalculationManual
Range("F2:F" & Cells(rows.Count, "F").End(xlUp).Row).Copy Destination:=Range("J2")
Range("F2:F" & Cells(rows.Count, "F").End(xlUp).Row).Copy Destination:=Range("K2")
ActiveSheet.Hyperlinks.Delete
For Each rng In Range("F2:F" & Cells(rows.Count, "F").End(xlUp).Row): rng.Value = LCase(rng.Value): Next rng
For Each rng In Range("K2:K" & Cells(rows.Count, "K").End(xlUp).Row): rng.Value = LCase(rng.Value): Next rng
For Each rng In Range("J2:J" & Cells(rows.Count, "J").End(xlUp).Row): rng.Value = LCase(rng.Value): Next rng
Dim cell As Range
lastRow = ActiveSheet.Cells(ActiveSheet.rows.Count, "C").End(xlUp).Row
For Each cell In ActiveSheet.Range("C2:C" & lastRow)
S = vbNullString
If cell.Value <> vbNullString Then
v = Split(cell.Value, " ")
For Each W In v
S = S & Left$(W, 1) & "."
Next W
cell.Offset(ColumnOffset:=-1).Value = S
End If
Next cell
Application.Range("B1").Value = "tesing"
Worksheets("Sheet1").Range("B1").Font.Bold = True
Columns("D").Replace What:="vander", _
Replacement:="van der", _
LookAt:=xlPart, _
SearchOrder:=xlByRows, _
MatchCase:=False, _
SearchFormat:=False, _
ReplaceFormat:=False
Columns("D").Replace What:="vanden", _
Replacement:="van den", _
LookAt:=xlPart, _
SearchOrder:=xlByRows, _
MatchCase:=False, _
SearchFormat:=False, _
ReplaceFormat:=False
Columns("B").Replace What:="..", _
Replacement:=".", _
LookAt:=xlPart, _
SearchOrder:=xlByRows, _
MatchCase:=False, _
SearchFormat:=False, _
ReplaceFormat:=False
Dim r As Range
For Each r In ActiveSheet.UsedRange
If Not IsError(r.Value) Then
v = r.Value
If v <> vbNullString Then
If Not r.HasFormula Then
r.Value = Trim(v)
End If
End If
End If
Next r
Dim i As Long
Dim DelRange As Range
On Error GoTo Whoa
Application.ScreenUpdating = False
For i = 1 To 50
If Application.WorksheetFunction.CountA(Range("A" & i & ":" & "Z" & i)) = 0 Then
If DelRange Is Nothing Then
Set DelRange = Range("A" & i & ":" & "Z" & i)
Else
Set DelRange = Union(DelRange, Range("A" & i & ":" & "Z" & i))
End If
End If
Next i
If Not DelRange Is Nothing Then DelRange.Delete shift:=xlUp
LetsContinue:
Application.ScreenUpdating = True
Exit Sub
Whoa:
MsgBox Err.Description
Resume LetsContinue
Worksheets("Sheet1").Columns("L").Replace _
What:=" ", _
Replacement:="", _
SearchOrder:=xlByColumns, _
MatchCase:=True
Application.EnableEvents = True
Application.ScreenUpdating = True
Application.Calculation = xlCalculationAutomatic
End Sub
Option Explicit
Private Sub Worksheet_Change(ByVal Target As Range)
Const RolesList As String = "Testing"
Const FirstCellAddress As String = "L2"
Const Delimiter As String = "||"
Dim rng As Range
With Range(FirstCellAddress)
Set rng = Intersect(.Resize(.Worksheet.rows.Count - .Row + 1), Target)
End With
If rng Is Nothing Then
Exit Sub
End If
Dim Roles() As String: Roles = Split(RolesList, ",")
Dim dRng As Range
Dim aRng As Range
Dim cel As Range
Dim Curr() As String
Dim cMatch As Variant
Dim n As Long
Dim isFound As Boolean
For Each aRng In rng.Areas
For Each cel In aRng.Cells
If Not IsError(cel) Then
Curr = Split(cel.Value, Delimiter)
For n = 0 To UBound(Curr)
cMatch = Application.Match(Curr(n), Roles, 0)
If IsError(cMatch) Then
isFound = True
Exit For
Else
If StrComp(Curr(n), Roles(cMatch - 1), _
vbBinaryCompare) <> 0 Then
isFound = True
Exit For
End If
End If
Next n
If isFound Then
isFound = False
If dRng Is Nothing Then
Set dRng = cel
Else
Set dRng = Union(dRng, cel)
End If
End If
End If
Next cel
Next aRng
Application.ScreenUpdating = False
rng.Interior.Color = xlNone
If Not dRng Is Nothing Then
dRng.Interior.Color = vbRed
End If
Application.ScreenUpdating = True
End Sub
Related
To give some context I got this module below. This module is also in my worksheet. Before starting the macro it works fine it highlights whenever there is not "Testing" in column L.
The problem: When I start my macro it does everything without error, but doesn't update.
So an example when I start it after the macro runs and is completed when I change "testing" into "Atesting" then it doesn't mark the cell red.
EDIT: Or when everything runs and is completed whenever I see "Atesting" in column L. I have to click the cell to see the change of the background becoming red.
Option Explicit
Private Sub Worksheet_Change(ByVal Target As Range)
Const RolesList As String = "Testing"
Const FirstCellAddress As String = "L2"
Const Delimiter As String = "||"
Dim rng As Range
With Range(FirstCellAddress)
Set rng = Intersect(.Resize(.Worksheet.Rows.Count - .Row + 1), Target)
End With
If rng Is Nothing Then
Exit Sub
End If
Dim Roles() As String: Roles = Split(RolesList, ",")
Dim dRng As Range
Dim aRng As Range
Dim cel As Range
Dim Curr() As String
Dim cMatch As Variant
Dim n As Long
Dim isFound As Boolean
For Each aRng In rng.Areas
For Each cel In aRng.Cells
If Not IsError(cel) Then
Curr = Split(cel.Value, Delimiter)
For n = 0 To UBound(Curr)
cMatch = Application.Match(Curr(n), Roles, 0)
If IsError(cMatch) Then
isFound = True
Exit For
Else
' Remove this block if you don't need case-sensitivity.
If StrComp(Curr(n), Roles(cMatch - 1), _
vbBinaryCompare) <> 0 Then
isFound = True
Exit For
End If
End If
Next n
If isFound Then
isFound = False
If dRng Is Nothing Then
Set dRng = cel
Else
Set dRng = Union(dRng, cel)
End If
End If
End If
Next cel
Next aRng
Application.ScreenUpdating = True
rng.Interior.Color = xlNone
If Not dRng Is Nothing Then
dRng.Interior.Color = vbRed
End If
Application.ScreenUpdating = True
End Sub
Maybe this helps, this is the whole code I'm using, are there any mistakes?
Before I start macro:
After I start macro:
After starting the macro it should still be red because it isn't in the role list, but it isn't't.
Sub AllInOne()
Application.EnableEvents = False
Application.ScreenUpdating = False
Application.Calculation = xlCalculationManual
Range("F2:F" & Cells(Rows.Count, "F").End(xlUp).Row).Copy Destination:=Range("J2")
Range("F2:F" & Cells(Rows.Count, "F").End(xlUp).Row).Copy Destination:=Range("K2")
ActiveSheet.Hyperlinks.Delete
For Each rng In Range("F2:F" & Cells(Rows.Count, "F").End(xlUp).Row): rng.Value = LCase(rng.Value): Next rng
For Each rng In Range("K2:K" & Cells(Rows.Count, "K").End(xlUp).Row): rng.Value = LCase(rng.Value): Next rng
For Each rng In Range("J2:J" & Cells(Rows.Count, "J").End(xlUp).Row): rng.Value = LCase(rng.Value): Next rng
Worksheets("sheet1").Columns("A:M").AutoFit
ActiveWorkbook.Worksheets("sheet1").UsedRange.Font.Underline = False
ActiveWorkbook.Worksheets("sheet1").Range("A2:Z5000").Font.Bold = False
ThisWorkbook.ActiveSheet.Cells.Range("A2:Z5000").ClearFormats
Range("A1:Z5000").Font.Color = vbBlack
Worksheets("sheet1").Columns("A:M").AutoFit
Dim cell As Range
lastRow = ActiveSheet.Cells(ActiveSheet.Rows.Count, "C").End(xlUp).Row
For Each cell In ActiveSheet.Range("C2:C" & lastRow)
S = vbNullString
If cell.Value <> vbNullString Then
v = Split(cell.Value, " ")
For Each W In v
S = S & Left$(W, 1) & "."
Next W
cell.Offset(ColumnOffset:=-1).Value = S
End If
Next cell
Application.Range("B1").Value = "testing"
Worksheets("sheet1").Range("B1").Font.Bold = True
Dim LastRowIndex As Integer
Dim RowIndex As Integer
Dim UsedRng As Range
Set UsedRng = ActiveSheet.UsedRange
LastRowIndex = UsedRng.Row - 1 + UsedRng.Rows.Count
Application.ScreenUpdating = False
For RowIndex = LastRowIndex To 1 Step -1
If Application.CountA(Rows(RowIndex)) = 0 Then
Rows(RowIndex).Delete
End If
Next RowIndex
Application.ScreenUpdating = False
Dim n As Long
Columns("D").Replace What:="vander", _
Replacement:="van der", _
LookAt:=xlPart, _
SearchOrder:=xlByRows, _
MatchCase:=False, _
SearchFormat:=False, _
ReplaceFormat:=False
Columns("D").Replace What:="vanden", _
Replacement:="van den", _
LookAt:=xlPart, _
SearchOrder:=xlByRows, _
MatchCase:=False, _
SearchFormat:=False, _
ReplaceFormat:=False
Columns("B").Replace What:="..", _
Replacement:=".", _
LookAt:=xlPart, _
SearchOrder:=xlByRows, _
MatchCase:=False, _
SearchFormat:=False, _
ReplaceFormat:=False
'Beta code'
Dim r As Range
For Each r In ActiveSheet.UsedRange
If Not IsError(r.Value) Then
v = r.Value
If v <> vbNullString Then
If Not r.HasFormula Then
r.Value = Trim(v)
End If
End If
End If
Next r
'NIEUW NIEUW NIEUW NIEUW NIEUW NIEUW NIEUW NIEUW '
Range("G2:G5000,A2:A5000,H2:H5000").Clear
Worksheets("sheet1").Columns("A:M").AutoFit
Application.EnableEvents = True
Application.ScreenUpdating = True
Application.Calculation = xlCalculationAutomatic
End Sub
Private Sub Worksheet_Change(ByVal Target As Range)
Const RolesList As String = "Testing"
Const FirstCellAddress As String = "L2"
Const Delimiter As String = "||"
Dim rng As Range
With Range(FirstCellAddress)
Set rng = Intersect(.Resize(.Worksheet.Rows.Count - .Row + 1), Target)
End With
If rng Is Nothing Then
Exit Sub
End If
Dim Roles() As String: Roles = Split(RolesList, ",")
Dim dRng As Range
Dim aRng As Range
Dim cel As Range
Dim Curr() As String
Dim cMatch As Variant
Dim n As Long
Dim isFound As Boolean
For Each aRng In rng.Areas
For Each cel In aRng.Cells
If Not IsError(cel) Then
Curr = Split(cel.Value, Delimiter)
For n = 0 To UBound(Curr)
cMatch = Application.Match(Curr(n), Roles, 0)
If IsError(cMatch) Then
isFound = True
Exit For
Else
' Remove this block if you don't need case-sensitivity.
If StrComp(Curr(n), Roles(cMatch - 1), _
vbBinaryCompare) <> 0 Then
isFound = True
Exit For
End If
End If
Next n
If isFound Then
isFound = False
If dRng Is Nothing Then
Set dRng = cel
Else
Set dRng = Union(dRng, cel)
End If
End If
End If
Next cel
Next aRng
Application.ScreenUpdating = True
rng.Interior.Color = xlNone
If Not dRng Is Nothing Then
dRng.Interior.Color = vbRed
End If
Application.ScreenUpdating = True
End Sub
I am trying to insert a blank row above a row that contains a specific word. But so far I can only insert it below this row.
Sub INSERTROW()
Dim c As Range
Dim lRow As Long
lRow = 1
Dim lRowLast As Long
Dim bFound As Boolean
With ActiveSheet
lRowLast = .Cells(.Rows.Count, 1).End(xlUp).Row
Do
Set c = .Range("A" & lRow)
If c.Value Like "*SEARCHED VALUE*" Then
bFound = True
ElseIf bFound Then
bFound = False
If c.Value <> "BLANKROW" Then
c.EntireRow.Insert
lRowLast = lRowLast + 1
c.Offset(-1, 0).Value = "BLANKROW"
c.Offset(-1, 0).Font.Color = RGB(0, 0, 0)
End If
End If
lRow = lRow + 1
Loop While lRow <= lRowLast + 1
End With
End Sub
It's easier and faster (AFAIK) if you use the find method.
See that I insert the row where the value is found and then I refer to the previous row with the offset function.
Finally, as a good practice, try to name your procedures and variables to something meaningful and indent your code (you may use www.rubberduckvba.com)
Public Sub InsertRowBeforeWord()
Dim findString As String
findString = "*SEARCHED VALUE*"
Dim lastRow As Long
lastRow = ActiveSheet.Cells(ActiveSheet.Rows.Count, 1).End(xlUp).Row
Dim searchRange As Range
Set searchRange = ActiveSheet.Range("A1:A" & lastRow)
Dim returnRange As Range
Set returnRange = searchRange.Find(What:=findString, _
After:=searchRange.Cells(searchRange.Cells.Count), _
LookIn:=xlValues, _
LookAt:=xlWhole, _
SearchOrder:=xlByRows, _
SearchDirection:=xlNext, _
MatchCase:=False)
If Not returnRange Is Nothing Then
returnRange.Offset(0, 0).EntireRow.Insert
returnRange.Offset(-1, 0).Value = "BLANKROW"
returnRange.Offset(-1, 0).Font.Color = RGB(0, 0, 0)
End If
End Sub
Let me know if it works.
I have a report where the "E" column has certain statuses. I only require one or two and I need to delete the rest. Is there a macro that can search column 'E' and delete from the following list if it matches?
DEAL_EXPIRED
DEAL_CLEARED
DEAL_AWAITING_AUTH
DEAL_AUTH_FAILED
Assuming your data has a header on the first row, you can use this:
Option Explicit
Sub DeleteMe()
Dim ws As Worksheet: Set ws = ThisWorkbook.Sheets("Sheet1")
Dim DeleteMe As Range, i As Long, ARR
ARR = ws.Range("E2:E" & ws.Range("E" & ws.Rows.Count).End(xlUp).Row).Value
For i = LBound(ARR) To UBound(ARR)
Select Case ARR(i, 1)
Case "DEAL_EXPIRED", "DEAL_CLEARED", "DEAL_AWAITING_AUTH", "DEAL_AUTH_FAILED"
If Not DeleteMe Is Nothing Then
Set DeleteMe = Union(DeleteMe, ws.Range("E" & i + 1))
Else
Set DeleteMe = ws.Range("E" & i + 1)
End If
End Select
Next i
If Not DeleteMe Is Nothing Then DeleteMe.EntireRow.Delete
End Sub
For this answer i use Sheet1.Try:
Option Explicit
Sub test()
Dim LR As Long
Dim i As Long
With ThisWorkbook.Worksheets("Sheet1")
LR = .Cells(.Rows.Count, "E").End(xlUp).Row
For i = LR To 1 Step -1
If .Range("E" & i).Value = "DEAL_EXPIRED" Or .Range("E" & i).Value = "DEAL_CLEARED" Or .Range("E" & i).Value = "DEAL_AWAITING_AUTH" Or .Range("E" & i).Value = "DEAL_AUTH_FAILED" Then
.Rows(i).EntireRow.Delete
End If
Next i
End With
End Sub
Option Explicit
Private D1 As Variant
Private RSel As Range
Private R2Del As Range
Public Sub Squadra_Unita(Optional ByVal msg As Variant) _
'https://youtu.be/sE6CMwO5Qm8
Rows_Delete _
Range_Walk( _
List_Ask( _
Selection_Check))
End Sub
Public Function Rows_Delete(Optional ByVal msg As Variant) _
As Variant
If R2Del Is Nothing Then _
Exit Function
R2Del.EntireRow.Delete shift:=xlUp
End Function
Public Function Range_Walk(Optional ByVal msg As Variant) _
As Range
Dim x As Long
For x = LBound(D1) To UBound(D1)
Set R2Del = App_Union( _
R2Del, _
Search_Get(RSel, D1(x)))
Next
End Function
Public Function Search_Get(ByVal r As Range, ByVal str As String) _
As Variant
Dim c As Range, found As Range, firstAddress As String
With r
Set c = .Find( _
what:=str, LookAt:=xlPart, MatchCase:=False)
If Not c Is Nothing Then
firstAddress = c.Address
Do
Set found = App_Union(found, c)
Set c = .FindNext(c)
If c Is Nothing Then Exit Do
Loop While c.Address <> firstAddress
End If
End With
If Not found Is Nothing Then _
Set Search_Get = found
End Function
Public Function List_Ask(Optional ByVal msg As Variant) As Variant ' Òåñòîì ÍÅ ïîêðûòà
Dim str As String
str = Application.InputBox( _
"Type words with space", _
"List for Delete Rows in Selection", , , , , , 2)
D1 = Split(str)
End Function
Public Function Selection_Check(Optional ByVal msg As Variant) _
As Variant
If Selection.Count < 2 Then
MsgBox "Need more selection :-)"
End
Else
Set RSel = Application.Intersect( _
ActiveSheet.UsedRange, _
Selection)
End If
End Function
Public Function App_Union(rng_Union As Range, _
ByVal rng As Range) _
As Range
' Set rng_union = App_Union(rng_union, .Rows(x))
If Not rng_Union Is Nothing Then
Set rng_Union = Application.Union(rng_Union, rng)
Else
Set rng_Union = rng
End If
Set App_Union = rng_Union
End Function
In my Column D i have numbers. Normally most of the rows for Col D will have single number eg 2 or 12 or 22 and so on. However on some occasion it will have two or more numbers eg 2, 4,12. The numbers in the cell are separated by commas.
Example:
Col D
Row1 1
Row2 4
Row3 2,12
Row4 11,1
Row5 2,1
Row6 3
Row7 21
Row8 1,11,15
Row9 10,1,9
Row10 1,16
How can I select
all the rows that has in Col D the number 1
ie in the above example it would select row1,row4,row5,row8,row9 and row10
Many thks
This will do it:
Sub SelectRows()
Dim lastRow As Long
Dim rng As Range, rw As Range
With ThisWorkbook.Sheets("test") ' change to your specific sheetname
lastRow = .Cells.Find(What:="*", _
SearchOrder:=xlRows, _
SearchDirection:=xlPrevious, _
LookIn:=xlValues).Row
For Each rw In .Columns("D").Rows
If InStr(1, rw.Value, "1") > 0 Then
If rng Is Nothing Then
Set rng = rw
Else
Set rng = Union(rng, rw)
End If
End If
If rw.Row = lastRow Then Exit For
Next rw
End With
rng.Select
End Sub
Edit #1
This improved code has no false positives as the earlier version:
Sub SelectRows()
Dim addBool As Boolean
Dim lastRow As Long, lenTempStr As Long
Dim rng As Range, rw As Range
Dim tempStr As Variant
With ThisWorkbook.Sheets("test") ' change to your specific sheetname
lastRow = .Cells.Find(What:="*", _
SearchOrder:=xlRows, _
SearchDirection:=xlPrevious, _
LookIn:=xlValues).Row
For Each rw In .Columns("D").Rows
addBool = False
tempStr = Replace(rw.Value, Chr(32), vbNullString)
lenTempStr = Len(tempStr)
If InStr(1, tempStr, "1") > 0 Then
If lenTempStr = 1 Then
addBool = True
ElseIf InStr(1, tempStr, ",1,") > 0 Then
addBool = True
ElseIf Left(tempStr, 2) = "1," Then
addBool = True
ElseIf Right(tempStr, 2) = ",1" Then
addBool = True
End If
If addBool Then
If rng Is Nothing Then
Set rng = rw
Else
Set rng = Union(rng, rw)
End If
End If
End If
If rw.Row = lastRow Then Exit For
Next rw
End With
rng.Select
End Sub
Sub Maybe_A()
Dim c As Range, i As Long, a As String
a = ""
For Each c In Range("D2:D" & Cells(Rows.Count, 4).End(xlUp).Row)
For i = LBound(Split(c, ",")) To UBound(Split(c, ","))
If Trim(Split(c, ",")(i)) = "1" Then
If a = "" Then
a = c.Address(0, 0)
Else
a = a & "," & c.Address
End If
Exit For
End If
Next i
Next c
Range(a).EntireRow.Select
End Sub
Many thks to all of you. Much appreciated. Below is the code which I came up with your help. Not sure how good it is and if it would do, although it seems to working. I had not seen select case true being used before!
Sub FindN()
Dim rC As Range, Rng As Range
Dim sFind As String, fC1 As String, fC2 As String, fC3 As String, fC4 As String
sFind = [d3].Value 'type the numeral to find in cell D3
'find criteria - i think there are four outcomes
fC1 = sFind: fC2 = sFind & ",*": fC3 = "*," & sFind & ",*": fC4 = "*," & sFind
Rng = Range("d4:d14")
Cells.EntireRow.Hidden = False
For Each rC In Rng
Select Case True
Case rC.Value = Val(fC1) 'for numeric 1
rC.EntireRow.Hidden = False
Case rC.Value Like fC2
rC.EntireRow.Hidden = False
Case rC.Value Like fC3
rC.EntireRow.Hidden = False
Case rC.Value Like fC4
rC.EntireRow.Hidden = False
Case Else
rC.EntireRow.Hidden = True
End Select
Next
End Sub
I have this code, but I'd like for it to find two adjacent cells with the values 7 and 2 (7 first in every pair) in column A and offset (from the 7) to the next column and insert a value to a specific row range.
Sub mark()
Dim FirstAddress As String
Dim MyArr As Variant
Dim Rng As Range
Dim I As Long
With Application
.ScreenUpdating = False
.EnableEvents = False
End With
MyArr = Array("X")
With Sheets("Sheet1").Range("A:A")
.Offset(0, 1).ClearContents
For I = LBound(MyArr) To UBound(MyArr)
Set Rng = .Find(What:=MyArr(I), _
After:=.Cells(.Cells.Count), _
LookIn:=xlFormulas, _
LookAt:=xlWhole, _
SearchOrder:=xlByRows, _
SearchDirection:=xlNext, _
MatchCase:=False)
If Not Rng Is Nothing Then
FirstAddress = Rng.Address
Do
Rng.Offset(0, 1).Value = "X"
Set Rng = .FindNext(Rng)
Loop While Not Rng Is Nothing And Rng.Address <> FirstAddress
End If
Next I
End With
With Application
.ScreenUpdating = True
.EnableEvents = True
End With
End Sub
Any suggestions appreciated.
Please try this code. I have expanded it to provide for specifying different results to be inserted at the found location.
Sub Mark2()
' 14 Feb 2018
Dim Ws As Worksheet
Dim Crits() As Variant
Dim Fun() As Variant
Dim MarkRng As Range
Dim R As Long
Dim i As Long
Dim Count As Integer
Set Ws = Worksheets("FindPair") ' replace with actual name
Crits = Array(7, 2, 13, 3, 17, 4) ' 1st, 2nd, 1st, 2nd, 1st, 2nd criterium
' Match the ranges in Fun() to the targets in Crits()
' 2 ranges for each Crit, each range 1 or more cells
' Omitted ranges must be represented by a comma
' Fun ranges specified in excess of available space will be ignored
' (for example, A32 + B28:B32 = 6 cells but MarkRng has only 5 cells)
Fun = Array("A32", "B28:B32", "A33:A35", "B33:B34", , "B100:B104")
With Application
.ScreenUpdating = False
.EnableEvents = False
End With
For i = LBound(Crits) To UBound(Crits) Step 2
Count = 0
Do
R = MatchRow(Crits(i), Ws, (R = 0))
If R Then
With Ws
If .Cells(R + 1, 1).Value = Crits(i + 1) Then
' column 2 = column B
Set MarkRng = Range(.Cells(R, 2), .Cells(R + 5, 2))
WriteResult i, Fun, MarkRng
Count = Count + 1
End If
End With
Else
If Count = 0 Then
MsgBox "No match was found for " & Crits(i), _
vbInformation, "Failure advice"
End If
Exit Do
End If
Loop
Next i
With Application
.ScreenUpdating = True
.EnableEvents = True
End With
End Sub
Private Function MatchRow(ByVal Crit As Variant, _
Ws As Worksheet, _
ByVal NewSearch As Boolean) As Long
' 13 Feb 2018
Static Rng As Range
Static Rstart As Long
Static Rend As Long
Dim Fnd As Range
With Ws
If NewSearch Then
Rstart = 2 ' start search in row 2
' find last used row
Rend = .Cells(.Rows.Count, 1).End(xlUp).Row
End If
Set Rng = Range(.Cells(Rstart, 1), .Cells(Rend, 1))
End With
With Rng
Set Fnd = .Find(What:=Crit, _
After:=.Cells(.Cells.Count), _
LookIn:=xlFormulas, _
LookAt:=xlWhole, _
SearchOrder:=xlByRows, _
SearchDirection:=xlNext, _
MatchCase:=False)
End With
If Not Fnd Is Nothing Then
MatchRow = Fnd.Row
Rstart = Fnd.Row + 1
End If
End Function
Private Sub WriteResult(ByVal Ix As Long, _
Fun() As Variant, _
Target As Range)
' 14 Feb 2018
Dim Ws As Worksheet
Dim Rng As Range, R As Long ' source
Dim Rt As Long
Dim i As Long
With Target
Set Ws = .Worksheet
For i = 0 To 1
If Not IsError(Fun(Ix + i)) Then
Set Rng = Ws.Range(Fun(Ix + i))
For R = 1 To Rng.Cells.Count
If Rt < .Cells.Count Then
Rt = Rt + 1
.Cells(Rt).Value = Rng.Cells(R).Value
End If
Next R
End If
Next i
End With
End Sub