Skip to content

Commit 803196d

Browse files
authored
Merge pull request #5 from Tavernari/add-regexp-predicate
Add regex string predicate with prefix =~
2 parents 5f1956d + 7c4b85f commit 803196d

5 files changed

Lines changed: 80 additions & 0 deletions

File tree

README.md

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -48,6 +48,15 @@ print(result7) // false
4848
// Check if text does NOT contain "cat" case insensitively and without diacritics
4949
let result8 = text.contains(!~"cat")
5050
print(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
Lines changed: 33 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,33 @@
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+

Sources/StringContainsOperators/SearchStrategyMaker.swift

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff 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

Sources/StringContainsOperators/StringContainsOperators.swift

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,7 @@ import Foundation
99
infix operator || : LogicalDisjunctionPrecedence
1010
infix operator && : LogicalConjunctionPrecedence
1111
prefix operator ~
12+
prefix operator =~
1213
prefix 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.

Tests/StringContainsOperatorsTests/StringContainsOperatorsTests.swift

Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff 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

0 commit comments

Comments
 (0)