Matching variations of a String using a single RegEx - ios

Is it possible to check for multiple variations of a string using a single Regular Expressions?
I want find matches of the following two string variations in a longer string.
yearly
every year
E.g.
"Do some clean up every year"
"Plan yearly clean up"
Currently my regex pattern looks like the following, working only for one specific variation
var pattern = "yearly"
var error: NSError?
var regularExpression = NSRegularExpression(pattern: pattern, options: .CaseInsensitive, error: &error)!
let matchingItems = regularExpression.matchesInString(entryString, options: nil, range:NSMakeRange(0, countElements(entryString)))
Can the matching of both cases ("yearly" + "every year") be combined using one Regular Expression or do I need two separate Regular Expressions for this?

var pattern = "yearly|(?:every year)"
You can try this way using | or operator.

Related

Regex Swift: How to find Two words OR Find Two words with a dash

I have two regex patterns in Swift, both work for each case separately:
case twoWords = "(#\w+\s\w+)" = #User Name
case twoWordsWithDash = "#(\w+\s\w+\-\w+)" = #User Name-Hyphen
Question:
How can I combine these two regex patterns in their respective strings, so the regex will configure EITHER twoWords or twoWordsWithDash??
What I want:
case twoWordsORtwoWordsWithDash = "(#\w+\s\w+)|#(\w+\s\w+\-\w+)" = #User Name OR #User Name-Hyphen
But this fails, that OR operator | doesn't seem to work..
You just need to switch the order so that the user name with dash has priority over the one without:
(#\w+\s\w+\-\w+)|(#\w+\s\w+)
You can check it using regex101

Search group of words in text field in CoreData

I am implementing an iOS app which contains a CoreData DB with one of the columns containing a text field, on which the user is supposed to perform several types of search (semantic, exact matches, among other options). Right now, I am stuck at trying to implement the following MySQL query (Python implementation):
'''select * from quotes where match section against ('\\"%s\\"' in boolean mode) ''' % (query)
The above query returns all the text rows containing all the words of string "query" without any particular order, as long as the text field contains all of the words. As an example, a query such as "tomorrow is Saturday" should find a match in a field containing the sentence "Saturday we are going somewhere. Tomorrow is Friday."
I have tried a few approaches, such as NSPredicate, and regex. I couldn't find a direct match in CoreData to the MySQL boolean mode, but the best I have been able to achieve so far was using regex with NSPredicate such as:
let queryArray = query.components(separatedBy: " ")
let regex = ".*\\b(" + queryArray.map {
NSRegularExpression.escapedPattern(for: $0)
}.joined(separator: "|") + ")\\b.*"
let predicate = NSPredicate(format: "textField MATCHES %#", regex)
However, this query is returning any textField row that contains one or more of the words in the initial query, which is not the desired result in my case.
How can I achieve the desired result in CoreData?
For those that may get stuck, NSCompoundPredicate did the trick for me, just create an array of predicates, where which NSPredicate instance is looking for one of the words in the string, ignoring case and apply the NSCompoundPredicate to the NSFetchRequest.

How to make predicate with dynamic where clause of SQL format

I have a requirement for the enterprise app that I'm working on where the SQL queries are stored in the system.
For example:
WORKTYPE not in('PM','PM1','EV','OP')
:worktype <>'PM' AND :worktype <>'PM1' AND
:worktype <>'EV' AND :worktype <>'OP'
WORKTYPE n :worktype are the attributes of an entity
PM, PM1, EV and OP are the values to be filtered
=======================================================================
These are some of example where clauses that I have to handle in the NSPredicate.
Programming Language: Swift 4
Database: Coredata
Any suggestion of how to handle these expressions ?
You can create NSPredicate at run time and at the end combine predicate using NSCompoundPredicate. Like in below syntax
let predicate = NSCompoundPredicate(andPredicateWithSubpredicates: [predicate1, predicate2])
BTW - I agree with the comments - you should provide more information in your question and explain what you have tried, including attempts at code, etc... however failing that...
Read about the NSExpression class, from the Apple Developer documentation...
NSExpression
An expression for use in a comparison predicate.
Overview
Comparison operations in an NSPredicate are based on two expressions, as represented by instances of the NSExpression class.
Expressions are created for constant values, key paths, and so on.
Although it is an archived document, Apple's "Predicate Programming Guide" is still relevant to those using predicates with Core Data in both Swift and Objective-C. I recommend you read it.
Within this documentation, I specifically point you to...
Creating Predicates > Creating Predicates Using Predicate Templates
The example from the documentation (translated to Swift)...
The following example uses a format string to create a predicate with
a right-hand side that is a variable expression.
let predicateTemplate = NSPredicate(format: "lastName like[c] %#", argumentArray: [$LAST_NAME])
This is equivalent to creating the variable expression directly as
shown in the following example.
let lhs = NSExpression(forKeyPath: "lastName"]
let rhs = NSExpression(forVariable: "LAST_NAME"]
let comparisonPredicate = NSComparisonPredicate(leftExpression: lhs,
rightExpression: rhs,
modifier: .direct,
type: .like,
options: [.caseInsensitive])
So enough of the lecture and to your question...
WORKTYPE not in('PM','PM1','EV','OP')
I assume here that you have the knowledge to parse your SQL expressions to extract the information set out in the first two lines of code below.
let keyPath: String = "WORKTYPE"
let arrayWorkTypes: [String] = ["PM", "PM1", "EV", "OP"]
var arrayComparisonPredicates = [NSPredicate]()
for workType in arrayWorkTypes {
let expressionLHS = NSExpression(forKeyPath: keyPath)
let expressionRHS = NSExpression(forConstantValue: workType)
let comparisonPredicate = NSComparisonPredicate(leftExpression: expressionLHS,
rightExpression: expressionRHS,
modifier: .direct,
type: .notEqualTo,
options: [.caseInsensitive])
arrayComparisonPredicates.append(comparisonPredicate)
}
let andPredicate = NSCompoundPredicate(andPredicateWithSubpredicates: arrayComparisonPredicates)
With your andPredicate built dynamically in this manner, you should be able to run your fetch request successfully.
I haven't tested this code so let me know how you go and I'll update if/when necessary.
And finally... your database is not Core Data.
If you’re using the Core Data framework in an Xcode project, your database is most likely SQLite.
Simply and according to Wikipedia, Core Data is “a model object graph and persistence framework...”
I highly recommend that you read and read and read some more until you truly understand the difference. I guarantee it will be a worthwhile investment of your time.

Regex NSRegularExpression vs NSPredicate

I was using a function to validate email format and password up till now
func isRegexValid(string:String,regex:String) -> Bool {
return NSPredicate(format: "SELF MATCHES %#", regex).evaluate(with: string)
}
I was trying to check a certain pattern and ran into problems. I was looking to find a string with 4 comma delimiters followed by "ext"
^(.*,){4}ext
The above function would not handle this as expected, so I tried an alternative which works well
func isRegexValid2(string:String,pattern:String) -> Bool {
let regex = try! NSRegularExpression(pattern: pattern, options: [])
return regex.firstMatch(in: string, options: [], range: NSMakeRange(0, string.utf16.count)) != nil
}
I would like to understand the differences between the two regex calls and whether we should avoid one or the other.
NSPredicate is very different from NSRegularExpression.
NSPredicate is used for searching and filtering among the Cocoa object. Its primary purpose is to filter certain object among a collection of objects. It has a completely different syntax.
As mentioned in the Apple docs for NSPredicate
Predicates represent logical conditions, which you can use to filter collections of objects.
For further study you can see Predicate programming guide.
On the other hand NSRegularExpression is a class that is used to compile regular expressions that are then applied to unicode strings.
NSRegularExpression class supports standard ICU regular expression defined at http://userguide.icu-project.org/strings/regexp
Hope this clarifies.

SQLite WHERE column MATCH parameter binding

I have FTS table and query that matches all rows where column contains both "all" and "in".
try db.executeQuery("SELECT * FROM table WHERE column MATCH '\"all\" AND \"in\"'", values: nil)
How can I make this work with parameter binding? So I can provide:
values: ["all", "in"]
SQLite uses plain strings as full-text patterns. You thus have to build yourself one full-text pattern string from your multiple words, and provide it as one FMDB parameter, as below.
let words = ["all", "in"]
let pattern = words
.map { "\"\($0)\"" } // wrap each word inside quotes
.joined(separator: " AND ")
try db.executeQuery("SELECT * FROM table WHERE column MATCH ?", values: [pattern])
Beware that not all patterns are valid. See the Full-Text Index Queries Grammar. This means that some inputs will trigger SQLite errors. For example, if the words come from a text field, and the user types a quote, as in "attack, then you may build the invalid pattern ""attack" that SQLite won't parse (SQLite error 1: malformed MATCH expression).
You can try to sanitize user input yourself, but this is difficult to do while preserving the maximum usable information. After all, application users are usually not aware of SQLite subtleties: there's no point punishing them with empty search results if they happen to type a funny search string.
If you need to perform pattern sanitization, I recommend you have a look at GRDB, an alternative to FMDB with great support for full-text search. It can build safe patterns from user input:
let userInput = textField.text
let pattern = FTS3Pattern(matchingAllTokensIn: userInput)
let rows = try Row.fetchAll(db, "SELECT * FROM table WHERE column MATCH ?", arguments: [pattern])
When user types "attack, the FTS3Pattern(matchingAllTokensIn:) would build the sane attack FTS pattern instead of failing. GRDB uses SQLite itself to perform the sanitization, which means that it's pretty solid.
For more information, see GRDB full-text search documentation.

Resources