What is syntax for placeholder usage in regular expression in Predicate? - ios

I want to specify my value in regular expression, how can I do it?
What I am doing:
request.predicate = Predicate(format: "entityProperty MATCHES [c] '[^0123]%#'", myValue)
Observing the result, I can say that %# is parsed as a characters in the regex string, no value is placed instead of it
Here is some explanation on usage of regular expressions with predicates, but no information about placeholders for values

Your Solution would work for:
myValue is representing valid regex pattern.
myValue may not contain single quotes (').
If myValue may contain single quote, this would work:
request.predicate = NSPredicate(format: "entityProperty MATCHES [c] %#", "[^1234]" + myValue)
And if myValue is not a regex pattern and may contain some meta-characters, you may need to write something like this:
request.predicate = NSPredicate(format: "entityProperty MATCHES [c] %#", "[^1234]"+NSRegularExpression.escapedPattern(for: myValue))
Anyway, you need to remember:
Single or double quoting variables (or substitution variable strings)
cause %#, %K, or $variable to be interpreted as a literal in the
format string and so prevent any substitution.
Parser Basics (Predicate Programming Guide)
(I used NSPredicate as Predicate is not available in Xcode 8 beta 6.)

request.predicate = Predicate(format: "entityProperty MATCHES [c] '[^0123]\(myValue)'")
Solution:
instead of %# placeholder use string substitution:
"prefixSomeText\(myValue)suffixSomeText"

Related

NSPredicate match string by words

I have an array of strings as below:
["Milk","Milkshake","Milk Shake","MilkCream","Milk-Cream"]
and if I search for "milk" then results should be ["Milk","Milk Shake","Milk-Cream"] i.e. search by words.
With the predicate as
NSPredicate *predicate = [NSPredicate predicateWithFormat:#"tagName CONTAINS[c] %#",containSearchTerm];
I am getting all the results from above array. How can I perform match using words ?
You need a “regular expression search” in order to match against word boundaries, that is done with "MATCHES" in a predicate. Here is an example (essentially translated from NSPredicate with core data, search word with boundaries in string attribute to Swift):
let searchTerm = "milk"
let pattern = ".*\\b\(NSRegularExpression.escapedPattern(for: searchTerm))\\b.*"
let predicate = NSPredicate(format: "tagName MATCHES[c] %#", pattern)
This searches for all entries where the tagName contains the given search term, surrounded by a “word boundary” (the \b pattern).

Validate a string using regex

I want to validate a string to check if it is alphanumeric and contains "-" and "." with the alphanumeric characters. So I have done something like this to form the regex pattern
NSRegularExpression *regex = [NSRegularExpression regularExpressionWithPattern:#"[a-zA-Z0-9\\.\\-]"
options:NSRegularExpressionCaseInsensitive
error:&error];
NSPredicate *regexTest = [NSPredicate predicateWithFormat:#"SELF MATCHES %#", regex];
BOOL valid = [regexTest evaluateWithObject:URL_Query];
App crashes stating that the regex pattern cannot be formed . Can anyone give me a quickfix to what am i doing wrong? Thanks in advance.
You must pass a variable of type NSString to the NSPredicate SELF MATCHES:
NSString * URL_Query = #"PAS.S.1-23-";
NSString * regex = #"[a-zA-Z0-9.-]+";
NSPredicate *regexTest = [NSPredicate predicateWithFormat:#"SELF MATCHES %#", regex];
BOOL valid = [regexTest evaluateWithObject:URL_Query];
See the Objective C demo
Note that you need no anchors with the SELF MATCHES (the regex is anchored by default) and you need to add + to match one or more allows symbols, or * to match 0+ (to also allow an empty string).
You do not need to escape the hyphen at the start/end of the character class, and the dot inside a character class is treated as a literal dot char.
Also, since both the lower- and uppercase ASCII letter ranges are present in the pattern, you need not pass any case insensitive flags to the regex.

Is there a way to check if a string contains a Unicode letter?

In Cocoa, regular expressions are presumably following the ICU Unicode rules for character matching and the ICU standard includes character properties such as \p{L} for matching all kinds of Unicode letters. However
NSString* str = #"A";
NSPredicate* pred = [NSPredicate predicateWithFormat:#"SELF MATCHES '\\p{L}'"];
NSLog(#"%d", [pred evaluateWithObject:str]);
doesn't seem to compile:
Can't do regex matching, reason: Can't open pattern U_REGEX_BAD_INTERVAL (string A, pattern p{L}, case 0, canon 0)
If character properties are not supported (are they?), how else could I check if a string contains a Unicode letter in my iOS app?
The main point here is that MATCHES requires a full string match, and also, \ backslash passed to the regex engine should be a literal backslash.
The regex can thus be
(?s).*\p{L}.*
Which means:
(?s) - enable DOTALL mode
.* - match 0 or more any characters
\p{L} - match a Unicode letter
.* - match zero or more characters.
In iOS, just double the backslashes:
NSPredicate * predicat = [NSPredicate predicateWithFormat:#"SELF MATCHES '(?s).*\\p{L}.*'"];
See IDEONE demo
If the backslashes inside the NSPrediciate are treated specifically, use:
NSPredicate * predicat = [NSPredicate predicateWithFormat:#"SELF MATCHES '(?s).*\\\\p{L}.*'"];

NSPredicate - Return inexact matches

In my app I allow users to search for vehicles by make/model using a textfield keyword search. Here is my predicate:
if (self.keywordSearch.text.length > 0) {
NSPredicate *predicate = [NSPredicate predicateWithFormat:#"fields.make CONTAINS[cd] %# OR fields.model CONTAINS[cd] %#", self.keywordSearch.text, self.keywordSearch.text];
self.vehicleArray = [[self.vehicleArray filteredArrayUsingPredicate:predicate] mutableCopy];
}
The problem is that if the Vehicle make/model is 'Ford F-150' and the user searches F150, or F 150, the vehicle isn't included in the results. It only returns if they search F-150 or f-150.
Is there a way to make sure these inexact matches are returning?
I suggest using regular expressions for this. You can either use a regular expression literal inside the NSPredicate format (described here: https://developer.apple.com/library/mac/documentation/Cocoa/Conceptual/Predicates/Articles/pUsing.html ) or you can iterate the array manually and use an NSRegularExpression for comparing the strings.

Predicate comparing two keys

I am trying to write a predicate to compare two keys in a cloud kit database. All the documentation I've been able to find only allows you to compare one key against a set value. Is there a way to write a predicate in swift to compare two keys?
The closest I've been able to come up with is:
let pred = NSPredicate(format: "%K == %K", "keyA", "keyB")!
but that keeps crashing on me.
use %# on R.H.S side insted of %k like this..
%# is a var arg substitution for an object value—often a string, number, or date.
%K is a var arg substitution for a key path.
let pred = (NSPredicate(format: "%K == %#", "keyA", "keyB")!)
Are you really trying to compare two keys? Or are you trying to compare the value associated with two keys? The difference between %# and %K in a predicate is that %# will be appropriately escaped, while %K won't be.
So:
NSPredicate(format:"value = %#", "Fred") // yields 'value = "Fred"'
While:
NSPredicate(format:"value = %K", "Fred") // yields 'value = Fred'
You want to use %K when you're passing an key name in as a parameter to the predicate, while you want to use '%#' if you're passing in a value.
From your example, title, and question, it's tough to figure out what you're actually trying to do, if you a predicate that insures that the value of two fields/keys is the same, you want to use
NSPredicate(format:"%K = %K", "key1", "key2")
as you're doing.
If you're trying to check that a particular key has a particular value, use:
NSPredicate(format:"%K = %#", "key1", "value1")
The code you've given, in isolation, executes just fine, where and what exactly is crashing, give us a bit more context.
With the further information that you're wanting to filter for records containing the same value in two different fields, it appears that CloudKit doesn't support field OP field only field OP constant Given that, the best work around I can suggest is:
let predicate = NSPredicate(format: "(gender1 = \"male\" AND gender2 = \"male\") OR (gender1 = \"female\" AND gender2 = \"female\")")

Resources