Skip to content

Commit 7ef8da8

Browse files
committed
Merge branch 'release/4.2.0' into versions
2 parents 0a66272 + bd2394c commit 7ef8da8

4 files changed

Lines changed: 57 additions & 1 deletion

File tree

Images/FreelanceKit.webp

68.3 KB
Loading

README.md

Lines changed: 16 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -38,13 +38,28 @@ I extracted most of this library from these Indie apps (rate them with 5 stars t
3838
</td>
3939
<td>
4040
<a href="https://apps.apple.com/app/apple-store/id6476773066?pt=549314&ct=github.com&mt=8">
41-
<strong>String Catalog Translator</strong>
41+
<strong>TranslateKit: App Localizer</strong>
4242
</a>
4343
<br />
4444
Simple drag & drop translation of String Catalog files with support for 4 machine translation services.
4545
</td>
4646
<td>Mac</td>
4747
</tr>
48+
<tr>
49+
<td>
50+
<a href="https://apps.apple.com/app/apple-store/id6480134993?pt=549314&ct=github.com&mt=8">
51+
<img src="https://raw.githubusercontent.com/FlineDev/HandySwift/main/Images/FreelanceKit.webp" width="64" />
52+
</a>
53+
</td>
54+
<td>
55+
<a href="https://apps.apple.com/app/apple-store/id6480134993?pt=549314&ct=github.com&mt=8">
56+
<strong>FreelanceKit: Time Tracking</strong>
57+
</a>
58+
<br />
59+
Simple & affordable time tracking with a native experience for all  devices. iCloud sync & CSV export included.
60+
</td>
61+
<td>iPhone, iPad, Mac, Vision</td>
62+
</tr>
4863
<tr>
4964
<td>
5065
<a href="https://apps.apple.com/app/apple-store/id6472669260?pt=549314&ct=github.com&mt=8">

Sources/HandySwift/Extensions/StringExt.swift

Lines changed: 39 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -183,6 +183,45 @@ extension String {
183183

184184
return plainString
185185
}
186+
187+
/// Splits the String into word tokens that are folded for case-insensitive, diacritics-insensitive, and width-insensitive operations such as search.
188+
/// This is particularly useful for string normalization in search queries, where the goal is to match strings regardless of their case, diacritics, or full-width/half-width characters.
189+
///
190+
/// - Parameter locale: Optional. The locale to use for the folding operation. If `nil`, the system's current locale is used. This affects the folding behavior, especially for diacritics.
191+
/// - Returns: An array of normalized, tokenized strings.
192+
///
193+
/// ## Example:
194+
/// ```
195+
/// let sentence = "Café au lait"
196+
/// let tokens = sentence.tokenized()
197+
/// print(tokens) // Output: ["cafe", "au", "lait"]
198+
/// ```
199+
public func tokenized(locale: Locale? = nil) -> [String] {
200+
self.components(separatedBy: .whitespacesAndNewlines).map { word in
201+
word.folding(options: [.caseInsensitive, .diacriticInsensitive, .widthInsensitive], locale: locale)
202+
}
203+
}
204+
205+
/// Splits both the current string and the search text into word tokens and performs a case-insensitive, diacritics-insensitive search.
206+
/// It matches the start of each token in the search text with the tokens in the current string, making it suitable for prefix-based search queries.
207+
///
208+
/// - Parameters:
209+
/// - searchText: The text to search for within this String.
210+
/// - locale: Optional. The locale to use for the insensitivity folding operation. If `nil`, the system's current locale is used. This can impact how characters are folded for comparison.
211+
/// - Returns: `true` if all tokens from the search text are prefixes of any token in this String; otherwise, `false`.
212+
///
213+
/// ## Example:
214+
/// ```
215+
/// let text = "Terms and Conditions"
216+
/// let searchResult = text.matchesTokenizedPrefixes(in: "ter con")
217+
/// print(searchResult) // Output: true
218+
/// ```
219+
public func matchesTokenizedPrefixes(in searchText: String, locale: Locale? = nil) -> Bool {
220+
let tokens = self.tokenized(locale: locale)
221+
return searchText.tokenized(locale: locale).allSatisfy { searchToken in
222+
tokens.contains { $0.hasPrefix(searchToken) }
223+
}
224+
}
186225
}
187226
#endif
188227

Sources/HandySwift/HandySwift.docc/Essentials/Extensions.md

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -292,6 +292,8 @@ func downloadPuzzle(from url: URL) async throws -> Puzzle {
292292
- ``Swift/String/randomElements(count:)``
293293
- ``Swift/String/encrypted(key:)``
294294
- ``Swift/String/decrypted(key:)``
295+
- ``Swift/String/tokenized(locale:)``
296+
- ``Swift/String/matchesTokenizedPrefixes(in:locale:)``
295297

296298
### StringProtocol
297299

0 commit comments

Comments
 (0)