Consider the following array:
NSArray *dataValues = #[#"Foo[0]", #"Foo[1].bar"];
And the following regex pattern, predicate and expected output:
NSString *pattern = #"Foo[0]";
NSPredicate *predicate = [NSPredicate predicateWithFormat: #"SELF BEGINSWITH[cd] %#", pattern];
NSArray *results = [dataValues filteredArrayUsingPredicate: predicate];
NSLog(#"matches = %ld", (long)results.count);
This prints 1 in the console as expected. If we change the pattern to:
NSString *pattern = #"Foo\\[[0-9]\\]";
I would expect this to print 2 in the console, but it prints 0. I have double escaped the outer square brackets to allow them to be parsed and expect to find strings that have the numbers 0 to 9 inside the brackets to match this expression.
I have checked the regex against the following site, which does work correctly:
http://regexr.com/3bcut
I have no warnings/errors in Xcode (6.4, 6E35b) running against the iOS 8.4 iPhone 6 Plus simulator, but why does my regex not filter as expected?
You could try this depending on what your needs are:
NSArray *dataValues = #[#"Foo[0]", #"Foo[1].bar"];
NSString *pattern = #"Foo[*]*";
NSPredicate *predicate = [NSPredicate predicateWithFormat: #"SELF LIKE %#", pattern];
NSArray *results = [dataValues filteredArrayUsingPredicate: predicate];
NSLog(#"matches = %ld", (long)results.count);
You could go a little more basic and use
NSMutableArray *results = [NSMutableArray array];
for (NSString *str in dataValues) {
if ([str rangeOfCharacterFromSet:[NSCharacterSet decimalDigitCharacterSet]].location != NSNotFound) {
if ([str hasPrefix:#"Foo["]) {
[results addObject:str];
}
}
}
NSLog(#"matches = %ld", (long)results.count);
After raising a TSI with Apple (well, who uses those things anyway?) they said I simply needed to use MATCHES instead of BEGINSWITH, which is only used for string matching - whereas I am trying to match on a regex.
My predicate should have therefore read:
NSPredicate *predicate = [NSPredicate predicateWithFormat: #"SELF MATCHES[cd] %#", pattern];
Related
Here is my test for filtering the array by a string. It work well if my string doesn't contain (') character
NSMutableArray *array = [NSMutableArray arrayWithObjects:#"Nick", #"b'en", #"Adam", #"Melissa", #"arbind", nil];
//NSPredicate *sPredicate = [NSPredicate predicateWithFormat:#"SELF contains[c] 'b'"]; -> it work
NSPredicate *sPredicate = [NSPredicate predicateWithFormat:#"SELF contains[c] 'b''"]; -> it crash
NSArray *beginWithB = [array filteredArrayUsingPredicate:sPredicate];
NSLog(#"beginwithB = %#",beginWithB);
I also try to change my string to 'b\'' or 'b''' but it still crash
Here is the crash log
Terminating app due to uncaught exception 'NSInvalidArgumentException', reason: 'Unable to parse the format string "SELF contains[c] 'b'''"'
How to resolve it? Any help would be great appreciated.
Please try to filter result as follows:
NSMutableArray *array = [NSMutableArray arrayWithObjects:#"Nick", #"b'en", #"Adam", #"Melissa", #"arbind", nil];
NSString *strToBeSearched = #"b'";
//NSPredicate *sPredicate = [NSPredicate predicateWithFormat:#"SELF contains[c] 'b'"]; -> it work
NSPredicate *sPredicate = [NSPredicate predicateWithFormat:#"SELF contains[c] %#",strToBeSearched]; //-> it also work
//OR
NSPredicate *sPredicate = [NSPredicate predicateWithFormat:#"SELF contains[c] 'b\\''"];
NSArray *beginWithB = [array filteredArrayUsingPredicate:sPredicate];
NSLog(#"containB = %#",beginWithB);
try this
NSString *searchword = #"b";
NSPredicate *sPredicate = [NSPredicate predicateWithFormat:#"SELF contains[c] %#",searchword];
you get output of
You were pretty close when you tried backslash. This is the character that NSPredicate uses to escape special characters. However, you need two, not one, backslash:
NSMutableArray *array = [NSMutableArray arrayWithObjects:#"Nick", #"b'en", #"Adam", #"Melissa", #"arbind", nil];
NSPredicate *sPredicate = [NSPredicate predicateWithFormat:#"SELF contains[c] 'b\\''"];
// ^^
NSArray *beginWithB = [array filteredArrayUsingPredicate:sPredicate];
NSLog(#"beginwithB = %#",beginWithB);
The reason you need two is Objective-C compiler. It processes all string literals in your code, and replaces escape sequences it encounters. If you would like NSPredicate to see a single backslash, your string literal needs to have two backslashes, because backslash itself is encoded as \\ in Objective-C string literals.
If your name is b'en then,
NSString *name = #"b'en";
NSPredicate *predicate = [NSPredicate predicateWithFormat:#"name == \"%#\"", name];
Hope this will help :)
I have a NSMutableArray containing NSString.
I need to filter only the objects that begins with (^WS|WV)[A-Z]{2}[0-9]{2}
How can I do it with NSPredicate?
Assuming that the array is called myArray, how can I write it?
Just google it to see a lot of answers like this:
NSArray *array = #[#"WSPS01", #"WLP05", #"1112"];
NSString *regex = #"(^WS|WV)[A-Z]{2}[0-9]{2}";
NSPredicate *pred = [NSPredicate predicateWithFormat:#"SELF MATCHES %#", regex];
NSArray *filteredArray = [array filteredArrayUsingPredicate:pred];
// filteredArray contains only WSPS01
array - its your NSMutableArray
Solved.
this is the correct regex:
NSString *regex = #"(^WS|WV|WC)[A-Z]{2}[0-9]{2}.*"
The only question that I still have is why the MATCHES operator works and the BEGINSWITH not...
I would like to know how if at all to use a compound NSPredicate?
I have made an attempt as follows however the currentInstall array is exactly the same at the start as it is after the predicate has been applied.
NSArray *currentInstall = [coreDataController filterReadInstalls:selectedInstallID];
NSArray *tempArray = [currentInstalls filteredArrayUsingPredicate:[NSPredicate predicateWithFormat:#"cHR == 0"]];
currentInstalls = [tempArray copy];
NSPredicate *predicateAreaString = [NSPredicate predicateWithFormat:#"area == %#", [myFilter objectForKey:#"area"]];
NSPredicate *predicateBString = [NSPredicate predicateWithFormat:#"stage == %#", [myFilter objectForKey:#"area2"]];
NSPredicate *predicateCString = [NSPredicate predicateWithFormat:#"partCode == %#", [myFilter objectForKey:#"area3"]];
NSPredicate *predicateDString = [NSPredicate predicateWithFormat:#"doorNo CONTAINS[cd] %#", [myFilter objectForKey:#"door"]];
NSPredicate *predicateEString = [NSPredicate predicateWithFormat:#"doorDesc CONTAINS[cd] %#", [myFilter objectForKey:#"doorDesc"]];
NSPredicate *compoundPredicate = [NSCompoundPredicate orPredicateWithSubpredicates:#[predicateAreaString, predicateBString, predicateCString, predicateDString, predicateEString]];
NSMutableArray *filteredArray = [NSMutableArray arrayWithArray:[currentInstalls filteredArrayUsingPredicate:compoundPredicate]];
currentInstalls = [filteredArray mutableCopy];
There doesn't seem to be anything obviously wrong with the way you have implemented NSCompundPredicate. If you are not trying to And or Not predicates then I would say it is something wrong with your predicate formats and how they match the array you are filtering.
I would try to use just 2 of the predicates to create an NSCompundPredicate then get that working or see what is causing your issue. NSHipster also has some good info about NSPredicates.
I need to append my custom string into NSPredicate.
So I wrote following codes.
self.query = [[NSMetadataQuery alloc] init];
[self.query setSearchScopes: [NSArray arrayWithObject:NSMetadataQueryUbiquitousDocumentsScope]];
NSPredicate *pred = [NSPredicate predicateWithFormat:#"%K like '%#*'",NSMetadataItemFSNameKey,whereAreYou];
NSLog(#"%#",pred.description);
[self.query setPredicate:pred];
However when I test it , it only return following value.
kMDItemFSName LIKE "%#*"
the placeholder %# is not append correctly. It only showing %# sign.
How can I do that?
Format arguments inside quotation marks are not expanded by predicateWithFormat,
therefore #"%K like '%#*'" does not work.
This should work:
NSString *pattern = [NSString stringWithFormat:#"%#*", whereAreYou];
NSPredicate *pred = [NSPredicate predicateWithFormat:#"%K LIKE %#", NSMetadataItemFSNameKey, pattern];
i'm trying to filter a string array with this predicate:
[NSPredicate predicateWithFormat:#"SELF LIKE[c] '#*!%d'", aNumber]
Every string which is like #WILDCARD!ANY_NUMBER is valid.
But it doesn't work :(
Can you help me?
EDIT:
NSString *pattern = [#"#*!" stringByAppendingFormat:#"%d", numberVariable];
NSPredicate *pred = [NSPredicate predicateWithFormat:#"SELF MATCHES %#", pattern];
NSArray *filteredArray = [anArray filteredArrayUsingPredicate:pred];
The array anArray contains Strings like #0!-1 (numberVariable is -1) but the array filterdArray is empty. So the regex doesn't work.
EDIT:
My Solution:
NSString *pattern = [#"#.*!\\" stringByAppendingFormat:#"%d", numberVariable];
NSPredicate *pred = [NSPredicate predicateWithFormat:#"SELF MATCHES %#", pattern];
NSArray *filteredArray = [anArray filteredArrayUsingPredicate:pred];
To find all strings that look like "#ANY_CHARACTERS!ANY_NUMBER" with an arbitrary number, you need the "MATCHES" operator with a regular expression:
NSPredicate *pred = [NSPredicate predicateWithFormat:#"SELF MATCHES %#", #"#.*!\\d+"];
NSArray *filtered = [yourArray filteredArrayUsingPredicate:pred];
If you have a specific number aNumber and want to find all strings of the form
"#ANY_CHARACTERS!<aNumber>", then the following should work:
NSString *pattern = [#"#*!" stringByAppendingFormat:#"%d", aNumber];
NSPredicate *pred = [NSPredicate predicateWithFormat:#"SELF LIKE %#", pattern];
NSArray *filtered = [yourArray filteredArrayUsingPredicate:pred];
The problem with your
[NSPredicate predicateWithFormat:#"SELF LIKE[c] '#*!%d'", aNumber]
is that %d inside quotation marks is not replaced by aNumber.