1

I am searching a column for cell that contains text and does not contain the word "cat" in the first 6 characters (needs to be case insensitive). This will then cut that entire row to another sheet. Cannot get the code to run without compile errors. the below code is before i try to change it. I do not know how to code it to look at the first 6 characters.

tried instr & iserror but i think my existing code just needs a small alteration which escapes me.

Sub CATDEFECTS()

UsdRws = Range("C" & Rows.Count).End(xlUp).Row

For i = UsdRws To 2 Step -1
        If Range("C" & i).Value Like "<>""" And Range("c" & i).Value Like "CAT" Then
            Rows(i).Cut Sheets("AWP DEFECTS").Range("A" & rows.Count).End(xlUp).Offset(1)
            Rows(i).Delete
        End If
        Next i

End Sub
Wesker
  • 13
  • 2
  • 1
    You're missing the wildcards in your `Like` statement - what you currently have will only match "CAT". Like is also case sensitive with the default comparison method (`Option Compare ...`). I'd suggest using [a regular expression](https://stackoverflow.com/questions/22542834/how-to-use-regular-expressions-regex-in-microsoft-excel-both-in-cell-and-loops) for this instead though. – Comintern Jan 29 '19 at 22:50

3 Answers3

2

Regardless of how you decide to implement the macro, your test to see if a cell is blank is entirely redundant. You can just test if the cell meets your CAT criteria. If it does, it is definitely not blank so no need to test it.


Method 1

You can look at the first 6 characters with LEFT(Range, 6)

If Left(Range("C" & i), 6) Like "*CAT*" Then

This needs Option Compare to work (Thanks @Comintern)


Method 2

I would prefer this method. Its explicit and does not delete or shift anything inside the loop so your action statements are greatly minimized.

Sub Cat()

Dim ws As Worksheet: Set ws = ThisWorkbook.Sheets("Sheet1") '<--UPDATE
Dim ps As Worksheet: Set ps = ThisWorkbook.Sheets("AWP DEFECTS")

Dim LR As Long, DeleteMe As Range, i As Long
LR = ws.Range("C" & ws.Rows.Count).End(xlUp).Row

For i = 2 To LR
    If InStr(Left(ws.Range("C" & i), 6), "CAT") Then
        If Not DeleteMe Is Nothing Then
            Set DeleteMe = Union(DeleteMe, ws.Range("C" & i))
        Else
            Set DeleteMe = ws.Range("C" & i)
        End If
    End If
Next i

Application.ScreenUpdating = False
    If Not DeleteMe Is Nothing Then
        LR = ps.Range("A" & ps.Rows.Count).End(xlUp).Row
        DeleteMe.EntireRow.Copy ps.Range("A" & LR)
        DeleteMe.EntireRow.Delete
    End If
Application.ScreenUpdating = True

End Sub
urdearboy
  • 14,439
  • 5
  • 28
  • 58
  • @urdearboy perfect i will keep a note of that. How do i make that code 'Not Like' "*CAT*"'? – Wesker Jan 29 '19 at 23:01
  • @Wesker if you see my second method, you can use `Not Like` by adding `Not` in front of `InStr`. Soooo `If Not InStr(......)` – urdearboy Jan 29 '19 at 23:12
  • wow thanks very much for your help! So the 2nd method basically marks those rows to be moved at the very end of the sub instead of there and then. Is that right? If so that may be a game changer as the rest of my VBA is very similar to that and is very very slow. – Wesker Jan 29 '19 at 23:22
  • & yes. Your code will have 2 actions every time a row meets your criteria (1 instance of copy, and 1 instance of delete). So say 500 rows meet your criteria. That means you have will 1,000 actions.The code I provided has 2 actions (1 instance of copy and 1 instance of delete) no matter how many rows meet your criteria. – urdearboy Jan 29 '19 at 23:24
  • im getting a invalid procedure call or argument for: Set DeleteMe = Union(DeleteMe, ws.Range("C" & i)) – Wesker Jan 29 '19 at 23:48
  • Did you check the sheet names – urdearboy Jan 30 '19 at 00:25
  • Yes they are correct. If I delete it all and repaste it and change the sheet name it works fine. I also tried to change If Not Instr & it just cuts everything. – Wesker Jan 30 '19 at 00:50
  • Can you post some sample strings so I can test. Reading it, it looks fine. I made up some test strings and this worked – urdearboy Jan 30 '19 at 00:53
  • I will post some tomorrow. Thanks for your interest & support. – Wesker Jan 30 '19 at 01:18
  • Your InStr requires vbtextcompare to be case-insensitive. The default is vbbinarycompare which is case-sensitive. –  Jan 30 '19 at 08:05
  • @user10981853 thanks for the tip, that works a treat. I only get the above error on this code when i put 'Not' infront of the 'InStr'. How do i get the above code to function with the 'Not', find everything that doesn't have 'Cat' excluding blank cells? – Wesker Jan 30 '19 at 18:10
0

If cat is within the first 6 characters then InStr will report its position being less than 5.

Sub CATDEFECTS()
    dim UsdRws  as long, pos as long

    UsdRws = Range("C" & Rows.Count).End(xlUp).Row

    For i = UsdRws To 2 Step -1

        pos =instr(1, cells(i, "C").value2, "cat", vbtextcompare)

        If pos > 0 and pos < 5 Then
            Rows(i).Cut Sheets("AWP DEFECTS").Range("A" & rows.Count).End(xlUp).Offset(1)
            Rows(i).Delete
        End If

    Next i

End Sub
0

Criteria Backup (Hide/Delete)

To enable the deletion of the rows in the Source Worksheet you have to set cDEL to True in the constants section. Adjust the other constants to fit you needs.

The Code

Option Explicit
'Option Compare Text

Sub CATDEFECTS()

    With Application
        .ScreenUpdating = False
        .Calculation = xlCalculationManual
    End With
    On Error GoTo ProcedureExit

    ' Source Constants
    Const cSource As Variant = "Sheet1"       ' Worksheet Name/Index
    Const cCol As Variant = "C"               ' Search Column Letter/Number
    Const cFirstR As Long = 2                 ' First Row Number
    Const cChars As Long = 6                  ' Number of Chars
    Const cSearch As String = "CAT"           ' Search String
    ' Target Constants
    Const cTarget As Variant = "AWP DEFECTS"  ' Worksheet Name/Index
    Const cColTgt As Variant = "A"            ' Column Letter/Number
    Const cFirstRTgt As Long = 2              ' First Row Number
    Const cDEL As Boolean = False             ' Enable Delete (True)
    ' Variables
    Dim rngH As Range     ' Help Range
    Dim rngU As Range     ' Union Range
    Dim vntS As Variant   ' Source Array
    Dim i As Long         ' Source Range Row Counter

    ' The Criteria
    ' When the first "cChars" characters do not contain the case-INsensitive
    ' string "cSearch", the criteria is met.

    ' Source Worksheet
    With ThisWorkbook.Worksheets(cSource)
        ' Calculate Last Cell in Search Column using the Find method and
        ' assign it to Help (Cell) Range.
        Set rngH = .Columns(cCol).Find("*", , xlFormulas, _
                xlWhole, xlByColumns, xlPrevious)
        ' Calculate Source Column Range from Help (Cell) Range.
        If Not rngH Is Nothing Then   ' Last Cell was found.
            ' Calculate Source Column Range and assign it to
            ' Help (Column) Range using the Resize method.
            Set rngH = .Cells(cFirstR, cCol).Resize(rngH.Row - cFirstR + 1)
            ' Copy Help (Column) Range into 2D 1-based 1-column Source Array.
            vntS = rngH
            ' Show hidden rows to prevent  the resulting rows (the rows to be
            ' hidden or deleted) to appear hidden in Target Worksheet.
            rngH.EntireRow.Hidden = False
          Else                        ' Last Cell was NOT found (unlikely).
            MsgBox "Empty Column '" & cCol & "'."
            GoTo ProcedureExit
        End If
        ' Loop through rows of Source Array.
        For i = 1 To UBound(vntS)
            ' Check if current Source Array value doesn't meet Criteria.
            If InStr(1, Left(vntS(i, 1), cChars), cSearch, vbTextCompare) = 0 _
                    Then ' "vbUseCompareOption" if "Option Compare Text"

            ' Note: To use the Like operator instead of the InStr function
            ' you have to use (uncomment) "Option Compare Text" at the beginning
            ' of the module for a case-INsensitive search and then outcomment
            ' the previous and uncomment the following line.
'            If Not Left(vntS(i, 1), cChars) Like "*" & cSearch & "*" Then

                Set rngH = .Cells(i + cFirstR - 1, cCol)
                If Not rngU Is Nothing Then
                    ' Union Range contains at least one range.
                    Set rngU = Union(rngU, rngH)
                  Else
                    ' Union Range does NOT contain a range (only first time).
                    Set rngU = rngH
                End If
            End If
        Next
    End With

    ' Target Worksheet
    If Not rngU Is Nothing Then ' Union Range contains at least one range.
        With ThisWorkbook.Worksheets(cTarget)
            ' Calculate Last Cell in Search Column using the Find method and
            ' assign it to Help Range.
            Set rngH = .Columns(cColTgt).Find("*", , xlFormulas, _
                    xlWhole, xlByColumns, xlPrevious)
            ' Calculate Last Cell from Help Range, but in column 1 ("A").
            If Not rngH Is Nothing Then   ' Last Cell was found.
                Set rngH = .Cells(rngH.Row + 1, 1)
              Else                        ' Last Cell was NOT found.
                Set rngH = .Cells(cFirstRTgt - 1, 1)
            End If
            ' Copy the entire Union Range to Target Worksheet starting from
            ' Help Range Row + 1 i.e. the first empty row (in one go).
            ' Note that you cannot Cut/Paste on multiple selections.
            rngU.EntireRow.Copy rngH
        End With
        ' Hide or delete the transferred rows (in one go).
        If cDEL Then  ' Set the constant cDEL to True to enable Delete.
            rngU.EntireRow.Delete
          Else        ' While testing the code it is better to use Hidden.
            rngU.EntireRow.Hidden = True
        End If
    End If

ProcedureExit:

    With Application
        .Calculation = xlCalculationAutomatic
        .ScreenUpdating = True
    End With

End Sub

Remarks

  • The use of the array did not speed up considerably.
  • The InStr function was a few milliseconds faster than the Like operator in my data set.
  • Calculating the Real Used Range and copying it into a Source Array and then writing the data that meets the criteria from Source Array to a Target Array and copying the Target Array to the Target Worksheet, might be faster, and/but would additionally copy the data without formulas or formatting.
VBasic2008
  • 44,888
  • 5
  • 17
  • 28