Home > Software engineering >  Text Filters on two string, But exclude some possibilities
Text Filters on two string, But exclude some possibilities

Time:01-23

I need to apply a text filtering on the string Mod* followed by a specific 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

CodePudding user response:

This isn't a perfect solution as it involves editing the source data before filtering it. However if you're ok with changing "C&H" to "C & H" in the data (so the H is always surrounded by spaces or at the end of the string)

Option Explicit
Option Compare Text
 
Sub Filter_Critr()

Const critr1 As String = "*Mod* H *"
Const critr2 As String = "*Mod* H"
 
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.replace "&", " & "
rng.AutoFilter Field:=3, Criteria1:=critr1, Operator:=xlOr, Criteria2:=critr2

ActiveWindow.ScrollColumn = 1
ActiveWindow.ScrollRow = 1
 
End Sub

CodePudding user response:

I also think that Autofilter is not able to do what you need. But AdvancedFilter should do it...

An unplesent aspect of AdvancedFilter is the fact that it needs a criteria Range, which cannot be replaced by an array. But, based on an array, such a range can be created, set and deleted at the end. Please, try the next code:

Sub AdvFilter_Critr()
   Dim ws As Worksheet, LRow As Long, LCol As Long, rng As Range, rngCrit As Range, arrCrit
   Const filtCol As Long = 3 'column to be filtered
   
   'build the criteria array, based on what to create a criteria range, which is able to admit more than two criteria strings using wildcard:
   arrCrit = Array("=""=*Mod *h*""", "=""=*Mod. *h*""", "=""=*Module *H*""", "=""=*model *h*""")

    Set ws = ActiveSheet
    If ws.AutoFilterMode Then ws.cells.AutoFilter 'completely clear AutoFilter...
    If ws.FilterMode Then ws.ShowAllData          'clear AdvancedFilter...

     LCol = ws.cells(2, ws.Columns.count).End(xlToLeft).column 'last col on the second row
     LRow = ws.cells(ws.rows.count, "A").End(xlUp).Row
      Set rng = ws.Range("A2:J" & LRow)
      ws.cells(2, LCol   2).Value = rng.cells(filtCol).value 'copy the criteria column header
      ws.cells(2, LCol   2).Offset(1).Resize(UBound(arrCrit)   1).Value = Application.Transpose(arrCrit) 'build the criteria range
      Set rngCrit = ws.cells(2, LCol   2).Resize(UBound(arrCrit)   2) 'set the criteria range

      rng.AdvancedFilter xlFilterInPlace, rngCrit 'place the advanced filter
    
      rngCrit.Clear 'clear the helper criteria range
End Sub

The above code assumes that the headers row is the second one!

CodePudding user response:

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.

  • Related