Search code examples
excelvbafilterstring-matching

Text Filters on two string, But exclude some possibilities


I need to apply a text filtering on the string Mod* followed by a specific one character e.g "H" , like:

(Mod h) , (Mod xxx H) , (Module x H) , (Mod H) , (Model xx H) and so on.

But: There are some unwanted cells are included on the result because it includes the string "Moderate" ,like:
(Moderate , Moderately).

So, I added a second filter to excludes that specific string "<>*Moderate*"

The problem: is that some cells could contain “Moderate” and Mod followed by one character, Like:
Moderate xxx Mod H and subsequently are not includes on filtered data.
although I need that cells on the expected result.

this is a test sample:

ID Description
beside chemical module h at eastern side
all moderately at mod H&B and north
Replace moderately at mod C&B and north
between Mod. A & Mod. H
Five moderately h pipe

and this is the expected result:

ID Description
beside chemical module h at eastern side
all moderately at mod H&B and north
between Mod. A & Mod. H

This is my code , I need to overcome this obstacle.

Option Explicit
Option Compare Text
 
Sub Filter_Critr()
 
    Const critr1 As String = "*Mod*H*"
    Const critr2 As String = "<>*Moderat*"
 
    Dim ws As Worksheet, LRow As Long, rng As Range
 
    Set ws = ActiveSheet
 
     LRow = ws.Cells(ws.Rows.Count, "A").End(xlUp).Row
      Set rng = ws.Range("A2:J" & LRow)                   'Source Range to apply Filter on it
 
    If Not ws.AutoFilterMode Then rng.AutoFilter          'Set AutoFilter if not already set
     ws.AutoFilter.ShowAllData
 
     rng.AutoFilter Field:=3, Criteria1:=critr1, Operator:=xlAnd, Criteria2:=critr2
 
       ActiveWindow.ScrollColumn = 1
       ActiveWindow.ScrollRow = 1
 
End Sub

Solution

  • Working with more than 2 criteria other than exact matching is not possible with autofilter. Instead, what about an helper column? For example, using a regular expression to be very explicit. Here is an example:

    Public Function RegexMatch(str, pat) As Boolean
    
    With CreateObject("vbscript.regexp")
        .pattern = pat
        RegexMatch = .Test(str)
    End With
    
    End Function
    

    Called at the worksheet level with:

    =RegexMatch(C2,"\b[Mm]od(?!erate).*\b[hH]\b")
    
    • \b - Word-boundary to assert that what follows is not preceded by other word-characters;
    • [Mm]od - Upper-/lowercase 'm' followed by 'od';
    • (?!erate) - Negative lookahead to assert position is not followed by 'erate';
    • .* - Any (0+, greedy) characters other than newline;
    • \b[hH]\b - Match upper-/lowercase letter 'h' and assert that it's a single letter substring with word-boundaries.

    See an online demo here. Now you can refer to these boolean values in your autofilter.