Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

What does NSString's isLike: actually do?

Tags:

I'm trying to figure out what isLike: actually does to NSStrings and having trouble. Apple's own documentation is very vague:

Returns a Boolean value that indicates whether the receiver is "like" another given object.

...

The default implementation for this method provided by NSObject method returns NO. NSString also provides an implementation of this method, which returns YES if the receiver matches a pattern described by object.

It mentions a "pattern", but with some rudimentary testing, it does not appear to be using regular expressions. What exactly is the pattern format in this case?

like image 670
Earlz Avatar asked Mar 09 '16 21:03

Earlz


People also ask

What does NSString mean?

A static, plain-text Unicode string object which you use when you need reference semantics or other Foundation-specific behavior.

What is NSString objective C?

(NSString *) is simply the type of the argument - a string object, which is the NSString class in Cocoa. In Objective-C you're always dealing with object references (pointers), so the "*" indicates that the argument is a reference to an NSString object.

How do I check if a string starts with Objective C?

A string object can be tested to identify whether the string begins or ends with a particular sequence of characters (otherwise known as prefixes and suffixes). This is achieved using the hasPrefix and hasSuffix methods respectively, both of which return boolean values based on whether a match is found or not.


2 Answers

As others have posted, Apple's documentation does not describe the behavior of [NSString isLike:] in detail as seen here:

The default implementation for this method provided by NSObject method returns NO. NSString also provides an implementation of this method, which returns YES if the receiver matches a pattern described by object.

As others suggested it may be based on NSPredicate. If so it is likely using NSComparisonPredicate with operator type NSLikePredicateOperatorType as described here:

NSMatchesPredicateOperatorType

A full regular expression matching predicate.

Available in OS X v10.4 and later.

NSLikePredicateOperatorType

A simple subset of the MATCHES predicate, similar in behavior to SQL LIKE.

Available in OS X v10.4 and later.

Although the functionality may be a simple subset of regular expressions, the syntax is definitely different. I tested the following locally on OS X 10.10.5 Today:

- (NSString *)escapeString:(NSString *)value {     return [value stringByReplacingOccurrencesOfString:@"\\" withString:@"\\\\"]; }  - (void)is:(NSString *)value like:(NSString *)pattern note:(NSString *)note {     NSLog(@"[@\"%@\" isLike:@\"%@\"] == %@ // %@",             [self escapeString:value],             [self escapeString:pattern],             ([value isLike:pattern] ? @"true" : @"false"),             note); }  - (void)testAll {     // each note contains result on OS X 10.10.5 on 20160503     [self is:@"foo" like:@"f*" note:@"true, '*' wildcard works like file globbing, not RE"];     [self is:@"foo" like:@"foo*" note:@"true, '*' is zero or more"];     [self is:@"foo" like:@"f?o" note:@"true, '?' wildcard works like file globbing, not RE"];     [self is:@"foo" like:@"f?" note:@"false, not more then one"];     [self is:@"foo" like:@"f?oo" note:@"false, not less than one"];     [self is:@"foo" like:@"Foo" note:@"false, is case-sensitive (also see isCaseInsensitiveLike:)"];     [self is:@"foo" like:@"[Ff]oo" note:@"true, supports character classes"];     [self is:@"foo" like:@"[^F]oo" note:@"false, does not support RE negation in character classes"];     [self is:@"foo" like:@"[a-z]oo" note:@"true, supports ranges"];     [self is:@"foo" like:@"[[:lower:]]oo" note:@"false, does not support POSIX named classes"];     [self is:@"]oo" like:@"[]]oo" note:@"false, does not support ']' as first character in a class"];     [self is:@"]oo" like:@"[\\]]oo" note:@"true, backslash to escape interpretation of ']' as end of class"];     [self is:@"[oo" like:@"\\[oo" note:@"true, backslash to escape interpretation as start of class"];     [self is:@"-oo" like:@"[x\\-z]oo" note:@"true, supports escape of '-' in character classes"];     [self is:@"?oo" like:@"\\?oo" note:@"true, escape with backslash"];     [self is:@"foo" like:@"\\?oo" note:@"false, this is not just wildcard matching"];     [self is:@"*oo" like:@"\\*oo" note:@"true, escape with backslash"];     [self is:@"foo" like:@"\\*oo" note:@"false, this is not just wildcard matching"];     [self is:@"\\foo" like:@"\\\\*oo" note:@"true, escape backslash with another backslash"]; } 

And this code produces these results:

[@"foo" isLike:@"f*"] == true // true, '*' wildcard works like file globbing, not RE [@"foo" isLike:@"foo*"] == true // true, '*' is zero or more [@"foo" isLike:@"f?o"] == true // true, '?' wildcard works like file globbing, not RE [@"foo" isLike:@"f?"] == false // false, not more then one [@"foo" isLike:@"f?oo"] == false // false, not less than one [@"foo" isLike:@"Foo"] == false // false, is case-sensitive (also see isCaseInsensitiveLike:) [@"foo" isLike:@"[Ff]oo"] == true // true, supports character classes [@"foo" isLike:@"[^F]oo"] == false // false, does not support RE negation in character classes [@"foo" isLike:@"[a-z]oo"] == true // true, supports ranges [@"foo" isLike:@"[[:lower:]]oo"] == false // false, does not support POSIX named classes [@"]oo" isLike:@"[]]oo"] == false // false, does not support ']' as first character in a class [@"]oo" isLike:@"[\\]]oo"] == true // true, backslash to escape interpretation of ']' as end of class [@"[oo" isLike:@"\\[oo"] == true // true, backslash to escape interpretation as start of class [@"-oo" isLike:@"[x\\-z]oo"] == true // true, supports escape of '-' in character classes [@"?oo" isLike:@"\\?oo"] == true // true, escape with backslash [@"foo" isLike:@"\\?oo"] == false // false, this is not just wildcard matching [@"*oo" isLike:@"\\*oo"] == true // true, escape with backslash [@"foo" isLike:@"\\*oo"] == false // false, this is not just wildcard matching [@"\\foo" isLike:@"\\\\*oo"] == true // true, escape backslash with another backslash 

So isLike: appears to support ? and * like file globbing with backslash \ to escape special interpretation. It also supports character classes with [ and ] with ranges defined with -. Backslash to escape opening [, and backslash to escape ] and - within the class.

like image 68
neuralmer Avatar answered Nov 17 '22 20:11

neuralmer


The header NSScriptWhoseTest.h provides a little more information:

@interface NSObject (NSComparisonMethods) ...  - (BOOL)isLike:(NSString *)object;     // argument should be a string using simple shell wildcards (* and ?).     // (e.g. "Stev*" or "N?XT").     // Returns NO if receiver is not an NSString.  - (BOOL)isCaseInsensitiveLike:(NSString *)object;  @end 
like image 38
Darren Avatar answered Nov 17 '22 22:11

Darren