Regex NSRegularExpression vs NSPredicate - ios

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.

Related

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.

NSPredicate that evaluates to true if an evaluated string contains 3 or more characters contained in a given string

The title pretty much says it - I am trying to write a predicate that can take a given string, and check whether or not another string contains at least three letters that my given string has. This is regardless of character order and capitalization, and includes duplicate occurrences of a letter. An example use of this would be, if I have a massive array of three letter words, I want to be able to pass a string with six characters (or an array of six, single character strings?) into this predicate and use it to evaluate whether or not any of the three letter words in my array are comprised of any three of the six letters I've passed in (duplicates included).
I was thinking it would be something along the lines of :
NSPredicate *predicate = [NSPredicate predicateWithFormat:#"SELF contains[cd] .{3,}%#",<array of characters>];
But I know that syntax is incorrect.
To check create the predicate, try
SWIFT:
let predicate = NSPredicate(format: "SELF contains %#", "abc")

Realm not query string field with whitespace

I have such function in my data source:
func getAllFood(by type: String) -> [UserFoodInformation] {
var findedFood = [UserFoodInformation]()
findedFood.append(contentsOf: baseUserFoodDataSource.getAllFood(by: type))
let predicate = NSPredicate(format: "foodType == %#", type)
let resultOfSearching = dataBase.objects(AddedUserFood.self).filter(predicate).sorted(byKeyPath: "name")
for searchedFood in resultOfSearching {
findedFood.append(searchedFood)
}
return findedFood
}
When I try to query with string that consist whitespace, I have no result, but if I query with simple one-word parameter, everything goes fine. Why is that? Can I have a string field in Realm that consists multiple words?
The predicate you're using is looking for objects whose foodType property is equal to the type string that is passed in. Only those objects whose property is exactly equal to that string will match. If you want to perform some other form of matching you'll need to use something other than the equality operator. BEGINSWITH, CONTAINS, ENDSWITH and LIKE are the comparison operators that Realm supports on string fields.
Can I have a string field in Realm that consists multiple words?
String fields can contain any string values. The supported comparison operators don't have the concept of a "word", though, so if you want to do filtering using that concept you'll likely need to do further work on your part. Depending on your use case, I can see a couple of ways to go about it:
Use CONTAINS to find any objects whose foodType properties contains the given type string.
Parse the string into structured data that you store in your model. For instance, it may make sense to store a List<FoodType> rather than a String for the foodType property.
There are likely other options, but they depend on details of what it is you're trying to achieve that you've not shared.

Matching variations of a String using a single RegEx

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.

Resources