写在前面
- 急着解决当前问题的开发同学,可以跳过,直接看后面的解决方法
场景
需求: 有一个字符串:@"今天我们来学习NSCharacterSet我们快乐",去除字符串中所有的@"今"、@"我"、@"s"、@"S"。
错误做法
NSString *str = @"今天我们来学习NSCharacterSet我们快乐";
NSString *str1 = @"我sS今";
NSMutableString *resultStr = [NSMutableString stringWithString:str];
for (int i = 0; i < str.length; i++) {
NSRange indexRange = NSMakeRange(i, 1);
NSString *indexStr = [str substringWithRange:indexRange];
if ([str1 containsString:indexStr]) {
if (indexRange.location != NSNotFound) {
NSLog(@"str.length = %lu",str.length);
NSLog(@"resultStr.length = %lu",resultStr.length);
NSLog(@"indexRange = %@",NSStringFromRange(indexRange));
[resultStr deleteCharactersInRange:indexRange];
}
}
}
报错
2018-09-12 03:46:23.686670+0800 NSCharacterSet[2414:36081] *** Terminating app due to uncaught exception 'NSRangeException', reason: '-[__NSCFString deleteCharactersInRange:]: Range or index out of bounds'
*** First throw call stack:
(
0 CoreFoundation 0x00007fff471482db __exceptionPreprocess + 171
1 libobjc.A.dylib 0x00007fff6e2e9c76 objc_exception_throw + 48
2 CoreFoundation 0x00007fff471d9d7d +[NSException raise:format:] + 205
3 CoreFoundation 0x00007fff47187945 mutateError + 261
4 NSCharacterSet 0x0000000100000ded main + 445
5 libdyld.dylib 0x00007fff6ef03015 start + 1
6 ??? 0x0000000000000001 0x0 + 1
)
libc++abi.dylib: terminating with uncaught exception of type NSException
(lldb)
原因分析
-
最直接的,新建一个Demo工程,是把我上面的代码复制进去运行,可以看到控制台的打印。
-
分析:可变字符串长度resultStr.length的数值是不断变化(减少)的,因为你一边遍历,一边删除。resultStr.length在减少,但你删除用的是长度不变的str.length的indexRange,这就很容易产生越界的crash
解决方法
方法一
- 使用可变字符串的长度resultStr.length
for (int i = 0; i < resultStr.length; i++) {
// 方法一,用变化(可变字符串)的字符串(resultStr)的长度
方法二(推荐)
- 逆序遍历
- 逆序遍历可以减少开发中很多越界问题,通用性很强
- 代码如下:
- 把遍历的地方改成下面的
for (int i = (int)str.length - 1 ; i >= 0; i--) {
// 方法二,使用原来的字符串(str.length)。 (强制转换(int),可去除警告⚠️:Implicit conversion loses integer precision: 'unsigned long' to 'int')
方法三
- 删除 -> 添加
NSString *str = @"今天我们来学习NSCharacterSet我们快乐";
NSString *str1 = @"我sS今";
NSMutableString *resultStr = [NSMutableString string];
for (int i = 0; i < str.length; i++) {
NSRange indexRange = NSMakeRange(i, 1);
NSString *indexStr = [str substringWithRange:indexRange];
if (![str1 containsString:indexStr]) {
// 方法三,创建一个新的可变字符串,删除操作改为添加操作
[resultStr appendString:indexStr];
}
}
方法四
- 使用NSCharacterSet
NSString *str2 = @"今天我们来学习NSCharacterSet我们快乐";
NSCharacterSet *characterSet = [NSCharacterSet characterSetWithCharactersInString:@"我sS今"];
NSArray *setArray = [str2 componentsSeparatedByCharactersInSet:characterSet];
NSLog(@"setArray = %@", setArray);
NSString *resultStr2 = [setArray componentsJoinedByString:@""];
NSLog(@"resultStr2 = %@", resultStr2);
方法五
- 字符串转化为数组,使用Block遍历
enumerateObjectsUsingBlock
方法N
- 欢迎补充
网友评论