#REFACTORING by cg
authorClaus Gittinger <cg@exept.de>
Thu, 02 May 2019 17:35:13 +0200
changeset 4938 48be5b40e700
parent 4936 1fec124a7fc7
child 4939 0d3a5e4dd07f
#REFACTORING by cg class: StringUtilities class added: #stringMatchFunctionFor:glob:regex:caseSensitive: refactored: multipattern search is useful for others
StringUtilities.st
--- a/StringUtilities.st	Thu Apr 04 10:48:03 2019 +0200
+++ b/StringUtilities.st	Thu May 02 17:35:13 2019 +0200
@@ -318,6 +318,155 @@
     "Modified (comment): / 09-08-2012 / 05:40:08 / cg"
 ! !
 
+!StringUtilities class methodsFor:'matching'!
+
+stringMatchFunctionFor:aMultiPattern glob:searchForGlobPattern regex:searchForRegexPattern caseSensitive:searchIsCaseSensitive
+    "generates a check function which - given a string - checks for a match;
+     The match may contain multiple patterns, separated by
+     ';' (for and-search) or '|' (for or-search).
+     If the pattern is invalid, nil is returned and an Information-notification
+     is signalled"
+
+    |combinator stringToSearchFor stringsToSearchFor checkFunction|
+
+    stringToSearchFor := aMultiPattern.
+    combinator := #conform:.
+    (stringToSearchFor includes:$|) ifTrue:[
+        stringsToSearchFor := stringToSearchFor asCollectionOfSubstringsSeparatedBy:$|.
+        combinator := #contains:.
+    ] ifFalse:[
+        (stringToSearchFor includes:$;) ifTrue:[
+            stringsToSearchFor := stringToSearchFor asCollectionOfSubstringsSeparatedBy:$;.
+        ] ifFalse:[
+            stringsToSearchFor := nil.
+"/            lastStringToSearchFor := self stringOfCurrentSearchList.
+"/            (lastStringToSearchFor notEmptyOrNil and:[stringToSearchFor startsWith:lastStringToSearchFor]) ifTrue:[
+"/                searchRoot := AbstractBrowserItemPO new.
+"/                self searchResultList do:[:each | searchRoot add:each treePO].
+"/                self stringOfCurrentSearchList:stringToSearchFor.
+"/                Transcript showCR:'fast'.
+"/            ].
+"/            self stringOfCurrentSearchList:stringToSearchFor.
+        ]
+    ].
+
+    Regex::RxParser regexErrorSignal handle:[:ex |
+        self notify:('Invalid regex Pattern.').
+        ^ nil
+    ] do:[
+        |lcString shortString regexPattern regexPatterns|
+
+        stringsToSearchFor isNil ifTrue:[
+            "/ single string search
+
+            (searchForGlobPattern and:[stringToSearchFor includesMatchCharacters]) ifTrue:[
+                |matchScanArray|
+
+                "/ verify if this is a valid pattern; if not, do not search
+                matchScanArray := String matchScanArrayFrom:stringToSearchFor escapeCharacter:String matchEscapeCharacter.
+                matchScanArray isNil ifTrue:[
+                    self information:'Invalid search pattern'.
+                    ^ nil.
+                ].
+
+                ((stringToSearchFor startsWith:$*) and:[(stringToSearchFor copyFrom:2) includesMatchCharacters not]) ifTrue:[
+                    shortString := (stringToSearchFor copyFrom:2).
+                    searchIsCaseSensitive ifTrue:[
+                        checkFunction := [:s | s endsWith:shortString].
+                    ] ifFalse:[
+                        lcString := shortString asLowercase.
+                        checkFunction := [:s | s asLowercase endsWith:lcString].
+                    ]
+                ] ifFalse:[
+                    ((stringToSearchFor endsWith:$*) and:[(stringToSearchFor copyButLast:1) includesMatchCharacters not]) ifTrue:[
+                        shortString := (stringToSearchFor copyButLast:1).
+                        searchIsCaseSensitive ifTrue:[
+                            checkFunction := [:s | s startsWith:shortString].
+                        ] ifFalse:[
+                            lcString := shortString asLowercase.
+                            checkFunction := [:s | s asLowercase startsWith:lcString].
+                        ]
+                    ] ifFalse:[
+                        regexPattern := searchIsCaseSensitive ifTrue:[stringToSearchFor asRegex] ifFalse:[stringToSearchFor asRegexIgnoringCase].
+                        checkFunction := [:s | regexPattern hasMatchesIn:s].
+                    ].
+                ].
+            ] ifFalse:[
+                searchForRegexPattern ifTrue:[
+                    regexPattern := searchIsCaseSensitive ifTrue:[stringToSearchFor asRegex] ifFalse:[stringToSearchFor asRegexIgnoringCase].
+                    checkFunction := [:s | regexPattern hasMatchesIn:s].
+                ] ifFalse:[
+                    checkFunction :=
+                        [:s | s includesString:stringToSearchFor caseSensitive:searchIsCaseSensitive]
+                ]
+            ].
+        ] ifFalse:[
+            "/ multi string search
+
+            searchForGlobPattern ifTrue:[
+                stringsToSearchFor do:[:eachStringToSearchFor |
+                    |matchScanArray|
+
+                    "/ verify if this is a valid pattern; if not, do not search
+                    matchScanArray := String matchScanArrayFrom:eachStringToSearchFor escapeCharacter:String matchEscapeCharacter.
+                    matchScanArray isNil ifTrue:[
+                        self information:'Invalid search pattern'.
+                        ^ nil.
+                    ].
+                ].
+
+                checkFunction :=
+                    [:s |
+                        stringsToSearchFor perform:combinator with:[:eachStringToSearchFor |
+                            s includesMatchString:eachStringToSearchFor caseSensitive:searchIsCaseSensitive
+                        ]
+                    ].
+            ] ifFalse:[
+                searchForRegexPattern ifTrue:[
+                    regexPatterns := stringsToSearchFor collect:[:eachPatternString|
+                                            searchIsCaseSensitive ifTrue:[eachPatternString asRegex] ifFalse:[eachPatternString asRegexIgnoringCase].
+                                        ].
+                    checkFunction := [:s | regexPattern hasMatchesIn:s].
+                    checkFunction :=
+                        [:s |
+                            regexPatterns perform:combinator with:[:eachRegexPattern |
+                                eachRegexPattern hasMatchesIn:s
+                            ]
+                        ].
+                ] ifFalse:[
+                    checkFunction :=
+                        [:s |
+                            stringsToSearchFor perform:combinator with:[:eachStringToSearchFor |
+                                s includesString:eachStringToSearchFor caseSensitive:searchIsCaseSensitive
+                            ]
+                        ]
+                ]
+            ].
+        ].
+    ].
+    ^ checkFunction
+
+    "
+     |fn|
+     fn := self stringMatchFunctionFor:'aaa|bbb' glob:false regex:false caseSensitive:false.
+     fn value:'   aaa   '.
+     fn value:'   aa   '.
+     fn value:'   bbb   '.
+     fn value:'  aa bb   '.
+     
+     fn := self stringMatchFunctionFor:'aaa;bbb' glob:false regex:false caseSensitive:false.
+     fn value:'   aaa   '.
+     fn value:'   aa   '.
+     fn value:'   bbb   '.
+     fn value:'  aa bb   '.
+     fn value:'  aaa bb   '.
+     fn value:'  aaa bbb   '.
+
+    "
+
+    "Created: / 02-05-2019 / 17:32:12 / Claus Gittinger"
+! !
+
 !StringUtilities class methodsFor:'queries'!
 
 isUtilityClass