如何在Objective-C中检查字符串是否包含另一个字符串?

1279

我该如何检查一个字符串(NSString)是否包含另一个更小的字符串?

我希望有类似这样的方法:

NSString *string = @"hello bla bla";
NSLog(@"%d",[string containsSubstring:@"hello"]);

但是我找到的最接近的是:

if ([string rangeOfString:@"hello"] == 0) {
    NSLog(@"sub string doesnt exist");
} 
else {
    NSLog(@"exists");
}

那么,这是查找字符串是否包含另一个字符串的最佳方法吗?


1
我也希望看到它被添加,但与此同时,在NSString上将其添加为类别相对容易。 - isaac
3
使用 if ([string rangeOfString:@"hello"] == 0) {...} 会导致 NSRange 和 int 类型不匹配的错误。要解决这个问题,您应该将该行更改为以下内容:if ([string rangeOfString:@"hello"].length == 0) {...} - Neeku
1
iOS 8 添加了 containsString: 方法,这里提供了一种最小侵入性的方法来支持 iOS 7。http://petersteinberger.com/blog/2014/retrofitting-containsstring-on-ios-7/ - Steve Moser
2
我从一开始就是iOS开发人员,经常回顾这篇文章以便快速复制粘贴。我似乎无法记住这个。这是我历史上访问最频繁的stackoverflow帖子。 - VaporwareWolf
21个回答

2491
NSString *string = @"hello bla bla";
if ([string rangeOfString:@"bla"].location == NSNotFound) {
  NSLog(@"string does not contain bla");
} else {
  NSLog(@"string contains bla!");
}

关键在于注意 rangeOfString: 返回一个 NSRange 结构体,并且文档表明,如果 "haystack" 不包含 "needle",则返回结构体 {NSNotFound, 0}


如果你在 iOS 8 或者 OS X Yosemite 上,现在可以这样做:*(注意:如果在 iOS7 设备上调用此代码将会导致应用程序崩溃)。

NSString *string = @"hello bla blah";
if ([string containsString:@"bla"]) {
  NSLog(@"string contains bla!");
} else {
  NSLog(@"string does not contain bla");
}

(这也适用于Swift)


288
要进行不区分大小写的搜索,请使用以下代码:如果([string rangeOfString:@"bla" options:NSCaseInsensitiveSearch].location!= NSNotFound) - Vanja
1
@Dave DeLong 在我看到你编辑答案之前,我正要提及我为此目的创建的一个类别!由于我主要是C#开发人员,我很高兴他们在NSString中添加了一个contains方法。 - dherrin79
3
补充@Vanja所说的:如果你要使用iOS 8/Yosemite中引入的[string containsString]快捷代码,可以使用以下代码进行不区分大小写的字符串搜索:"[stringToSearch localizedCaseInsensitiveContainsString:string]",如果您想进行不区分大小写和音符的搜索,则可以使用此代码:"[stringToSearch localizedStandardContainsString:string]"。 - Scott Kohlert
1
请注意,当字符串为nil时,表达式[string rangeOfString:@"bla"].location != NSNotFound将为true - funroll
为了保持对iOS7的支持,可以动态添加containsString:方法。对于iOS8+,这段代码不会起作用,而是使用真正的containsString:方法。- (void)setupContainsString { SEL containsStringSelector = @selector(containsString:); IMP containsStringIMP = imp_implementationWithBlock(^(id _self, NSString *string) {\ NSRange range = [_self rangeOfString:string]; return range.length != 0; }); //仅在类没有实现该方法时才添加该方法 class_addMethod([NSString class], containsStringSelector, containsStringIMP, "c@@:"); } - Kamil.S
显示剩余2条评论

167

对于iOS 8.0+和macOS 10.10+,您可以使用NSString的本地containsString:

对于旧版本的iOS和macOS,您可以为NSString创建自己的(已过时)类别:

@interface NSString ( SubstringSearch )
    - (BOOL)containsString:(NSString *)substring;
@end

// - - - - 

@implementation NSString ( SubstringSearch )

- (BOOL)containsString:(NSString *)substring
{    
    NSRange range = [self rangeOfString : substring];
    BOOL found = ( range.location != NSNotFound );
    return found;
}

@end

注意:请注意下面 Daniel Galasko 的评论中的命名问题。


13
+1 表示支持更清晰的代码和可重用性。我把它变成了一行代码 return [self rangeOfString:substring].location != NSNotFound; 并将其包含在我的重构库 es_ios_utils 中。https://github.com/peterdeweese/es_ios_utils - Peter DeWeese
4
看起来苹果公司喜欢你的想法,并在iOS 8和OSx 10.10(Yosemite)中添加了此功能,正如@DaveDeLong在他的答案中所提到的。+1 - Islam
8
Objective-C 类别的基本规则是在方法名前加上三个字母的模块前缀。这是一个完美的例子,因为它现在与 iOS 7 和 10.10 版本冲突了。 - Daniel Galasko

59

鉴于此在Google中似乎是排名较高的结果,我想添加以下内容:

iOS 8和OS X 10.10向NSString添加了containsString:方法。以下是Dave DeLong针对这些系统的示例的更新版本:

NSString *string = @"hello bla bla";
if ([string containsString:@"bla"]) {
    NSLog(@"string contains bla!");
} else {
    NSLog(@"string does not contain bla");
}

41
NSString *myString = @"hello bla bla";
NSRange rangeValue = [myString rangeOfString:@"hello" options:NSCaseInsensitiveSearch];

if (rangeValue.length > 0)
{
    NSLog(@"string contains hello");
} 
else 
{
    NSLog(@"string does not contain hello!");
}

//你也可以使用以下方法:

if (rangeValue.location == NSNotFound) 
{
    NSLog(@"string does not contain hello");
} 
else 
{
    NSLog(@"string contains hello!");
}

24

使用 iOS 8Swift,我们可以使用 localizedCaseInsensitiveContainsString 方法

 let string: NSString = "Café"
 let substring: NSString = "É"

 string.localizedCaseInsensitiveContainsString(substring) // true

1
这很好。不知道为什么他们在iOS 7中没有这种方法。 - Lucas
@Lucas,因为Swift是在iOS 8.0推出的。但是使用Swift仍然可以支持iOS 7设备。 - Hemang

13
个人而言,我真的很讨厌NSNotFound,但我理解它的必要性。但有些人可能不了解与NSNotFound进行比较的复杂性。例如,这段代码:
- (BOOL)doesString:(NSString*)string containString:(NSString*)otherString {
    if([string rangeOfString:otherString].location != NSNotFound)
        return YES;
    else
        return NO;
}

有问题的英文原句为:

has its problems:

1) Obviously if otherString = nil this code will crash. a simple test would be:

其中 otherString = nil 表示代码中的一个变量等于空值(nil),如果这种情况发生,代码将会崩溃。可以通过简单的测试来验证。
NSLog(@"does string contain string - %@", [self doesString:@"hey" containString:nil] ? @"YES": @"NO");

结果是 !!崩溃!!

2)对于新接触Objective-C的人来说,不太明显的是当string = nil时,相同的代码将不会崩溃。例如,以下代码:

NSLog(@"does string contain string - %@", [self doesString:nil containString:@"hey"] ? @"YES": @"NO");

这段代码:
NSLog(@"does string contain string - %@", [self doesString:nil containString:nil] ? @"YES": @"NO");

将会导致两者都。
does string contains string - YES

这段文字的英译中文如下:

这显然不是你想要的。

因此,我认为更好的解决方案是利用rangeOfString返回0的长度,因此更可靠的代码应该是这样的:

- (BOOL)doesString:(NSString*)string containString:(NSString*)otherString {
    if(otherString && [string rangeOfString:otherString].length)
        return YES;
    else
        return NO;
}

或者简单地说:
- (BOOL)doesString:(NSString*)string containString:(NSString*)otherString {
    return (otherString && [string rangeOfString:otherString].length);
}

这句话的意思是:“对于情况1和2,它将返回...”。
does string contains string - NO

那是我的两分钱 ;-)
请查看我的Gist获取更多有用的代码。

12

一个改进版的P i的解决方案,是NSString的一个类别,它不仅可以告诉我们一个字符串是否存在另一个字符串中,还可以通过引用获取范围:

@interface NSString (Contains)
-(BOOL)containsString: (NSString*)substring
              atRange:(NSRange*)range;

-(BOOL)containsString:(NSString *)substring;
@end

@implementation NSString (Contains)

-(BOOL)containsString:(NSString *)substring
              atRange:(NSRange *)range{

    NSRange r = [self rangeOfString : substring];
    BOOL found = ( r.location != NSNotFound );
    if (range != NULL) *range = r;
    return found;
}

-(BOOL)containsString:(NSString *)substring
{
    return [self containsString:substring
                        atRange:NULL];
}

@end

使用方法如下:

NSString *string = @"Hello, World!";

//If you only want to ensure a string contains a certain substring
if ([string containsString:@"ello" atRange:NULL]) {
    NSLog(@"YES");
}

// Or simply
if ([string containsString:@"ello"]) {
    NSLog(@"YES");
}

//If you also want to know substring's range
NSRange range;
if ([string containsString:@"ello" atRange:&range]) {
    NSLog(@"%@", NSStringFromRange(range));
}

7

一行代码(更少的代码量,DRY原则,只使用一个NSLog):

NSString *string = @"hello bla bla";
NSLog(@"String %@", ([string rangeOfString:@"bla"].location == NSNotFound) ? @"not found" : @"cotains bla"); 

7

以下是一个复制粘贴的函数片段:

-(BOOL)Contains:(NSString *)StrSearchTerm on:(NSString *)StrText
{
    return [StrText rangeOfString:StrSearchTerm 
        options:NSCaseInsensitiveSearch].location != NSNotFound;
}

我可以知道为什么我被踩了吗?这是一个可行的代码片段。 - Durai Amuthan.H

5
NSString *categoryString = @"Holiday Event";
if([categoryString rangeOfString:@"Holiday"].location == NSNotFound)
{
    //categoryString does not contains Holiday
}
else
{
    //categoryString contains Holiday
}

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接