File tree Expand file tree Collapse file tree
Sources/StringContainsOperators
Tests/StringContainsOperatorsTests Expand file tree Collapse file tree Original file line number Diff line number Diff line change @@ -48,6 +48,15 @@ print(result7) // false
4848// Check if text does NOT contain "cat" case insensitively and without diacritics
4949let result8 = text.contains (!~ " cat" )
5050print (result8) // true
51+
52+ // Check if text contains "quick" OR "jumps" AND "fox" using a regular expression
53+ let result9 = text.contains (=~ " (quick|jumps).*fox" )
54+ print (result9) // true
55+
56+ // Check if text contains "jumps" OR "swift" AND "fox" using a regular expression
57+ let result10 = text.contains (=~ " (jumps|swift).*fox" )
58+ print (result10) // true
59+
5160```
5261
5362## How to Install
Original file line number Diff line number Diff line change 1+ //
2+ // RegexSearchStrategy.swift
3+ //
4+ //
5+ // Created by Victor C Tavernari on 24/03/2023.
6+ //
7+
8+ import Foundation
9+
10+ /// A search strategy that evaluates whether a string matches a given regular expression pattern.
11+ final class RegexSearchStrategy : SearchStrategy {
12+
13+ /// The regular expression pattern to match.
14+ let regex : NSRegularExpression ?
15+
16+ /// Creates a new instance of `RegexSearchStrategy` with the given regular expression pattern.
17+ /// - Parameter pattern: The regular expression pattern to match.
18+ init ( pattern: String ) {
19+
20+ self . regex = try ? NSRegularExpression ( pattern: pattern,
21+ options: [ ] )
22+ }
23+
24+ /// Evaluates whether a string matches the regular expression pattern.
25+ /// - Parameter string: The string to evaluate.
26+ /// - Returns: `true` if the string matches the regular expression pattern, `false` otherwise.
27+ func evaluate( string: String ) -> Bool {
28+
29+ let range = NSRange ( location: 0 , length: string. utf16. count)
30+ return self . regex? . firstMatch ( in: string, options: [ ] , range: range) != nil
31+ }
32+ }
33+
Original file line number Diff line number Diff line change @@ -39,6 +39,9 @@ enum SearchStrategyMaker {
3939 case let . diacriticAndCaseInsensitive( value) :
4040 return DiacriticAndCaseInsensitiveSearchStrategy ( value: value)
4141
42+ case let . regexp( pattern) :
43+ return RegexSearchStrategy ( pattern: pattern)
44+
4245 case let . negatable( value) :
4346 return NegatableValueSearchStrategy ( value: value)
4447
Original file line number Diff line number Diff line change @@ -9,6 +9,7 @@ import Foundation
99infix operator || : LogicalDisjunctionPrecedence
1010infix operator && : LogicalConjunctionPrecedence
1111prefix operator ~
12+ prefix operator =~
1213prefix operator !
1314
1415/// An enum representing a string search predicate.
@@ -35,8 +36,14 @@ public indirect enum StringPredicate {
3536 /// Represents a case-insensitive and diacritic-insensitive search for a given string.
3637 case diacriticAndCaseInsensitive( String )
3738
39+ /// Represents a regular expression pattern that can be used to match a string using NSRegularExpression.
40+ /// - Note: The String value should be a valid regular expression pattern.
41+ case regexp( String )
42+
43+ /// Represents a negatable search predicate for a given string.
3844 case negatable( String )
3945
46+ /// Represents a negatable search predicate for a given `StringPredicate`.
4047 case negatablePredicate( StringPredicate )
4148}
4249
@@ -129,6 +136,15 @@ public prefix func ~ (value: String) -> StringPredicate {
129136 return . diacriticAndCaseInsensitive( value)
130137}
131138
139+ /// Returns a `StringPredicate` that performs a regular expression pattern that can be used to match a string using NSRegularExpression.
140+ ///
141+ /// - Parameter value: The regular expression pattern as a string value.
142+ /// - Returns: A `StringPredicate` that can be used to perform regular expression pattern matching.
143+ public prefix func =~ ( value: String ) -> StringPredicate {
144+
145+ return . regexp( value)
146+ }
147+
132148/// Returns a `StringPredicate` that negates another `StringPredicate`.
133149///
134150/// - Parameter predicate: The predicate to be negated.
Original file line number Diff line number Diff line change @@ -103,6 +103,25 @@ final class StringContainsOperatorsTests: XCTestCase {
103103 XCTAssertFalse ( " Goodbye " . contains ( predicate) )
104104 }
105105
106+ func testContainsWithRegexp( ) {
107+
108+ let string = " This is a test string "
109+
110+ let predicate = " test " && " string " && =~ " is.a "
111+
112+ XCTAssertTrue ( string. contains ( predicate) )
113+
114+ let invalidString = " This is not a valid string "
115+ XCTAssertFalse ( invalidString. contains ( predicate) )
116+ }
117+
118+ func testWithInvalidRegexp( ) {
119+
120+ let string = " This is a test string "
121+
122+ XCTAssertFalse ( string. contains ( =~ " ^*$(dis.a " ) )
123+ }
124+
106125 func testNegatablePredicate( ) {
107126 let text = " Hello my little friend "
108127
You can’t perform that action at this time.
0 commit comments