Подтвердить что ты не робот

Что делает NSString как-то: на самом деле?

Я пытаюсь понять, что isLike: действительно делает с NSString и имеет проблемы. Apple собственная документация очень расплывчата:

Возвращает логическое значение, указывающее, является ли приемник "как" другой заданный объект.

...

Реализация по умолчанию для этого метода, предоставляемая методом NSObjectвозвращает NO. NSString также обеспечивает реализацию этого метода, который возвращает YES, если приемник соответствует шаблону, описанному в объект.

Он упоминает "шаблон", но с некоторым рудиментарным тестированием он, похоже, не использует регулярные выражения. Что такое формат шаблона в этом случае?

4b9b3361

Ответ 1

Как и другие публикации, документация Apple не описывает поведение [NSString isLike:] подробно, как показано здесь:

Реализация по умолчанию для этого метода, предоставляемая методом NSObject, возвращает NO. NSString также предоставляет реализацию этого метода, который возвращает YES, если получатель соответствует шаблону, описанному объектом.

Как полагают другие, он может быть основан на NSPredicate. Если это так, скорее всего, с помощью NSComparisonPredicate с типом оператора NSLikePredicateOperatorType, как описано здесь:

NSMatchesPredicateOperatorType

Полный предикат, соответствующий правильному выражению.

Доступно в OS X версии 10.4 и более поздних версиях.

NSLikePredicateOperatorType

Простой подмножество предиката MATCHES, аналогичный поведению SQL LIKE.

Доступно в OS X версии 10.4 и более поздних версиях.

Хотя функциональность может быть простым подмножеством регулярных выражений, синтаксис определенно отличается. Я тестировал следующее локально на OS X 10.10.5 Сегодня:

- (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"];
}

И этот код дает следующие результаты:

[@"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

Итак, isLike:, как представляется, поддерживает ? и * как файловое сглаживание с обратным слэшем \, чтобы избежать специальной интерпретации. Он также поддерживает классы символов с [ и ] с диапазонами, определенными с помощью -. Обратная косая черта, чтобы избежать открытия [, и обратная косая черта, чтобы избежать ] и - внутри класса.

Ответ 2

Заголовок NSScriptWhoseTest.h предоставляет немного больше информации:

@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