NSString&NSRange&NSCharacterSet
- NSString
-
- NSRange
-
- [一、NSRange 核心定义](#一、NSRange 核心定义)
- [二、NSRange 核心使用场景](#二、NSRange 核心使用场景)
- [三、NSRange 与其他类型的转换](#三、NSRange 与其他类型的转换)
- [四、NSRange 实战使用示例](#四、NSRange 实战使用示例)
-
- [五、NSRange 常见坑点](#五、NSRange 常见坑点)
- 总结
- NSCharacterSet
-
- [一、NSCharacterSet 核心定义](#一、NSCharacterSet 核心定义)
- 二、核心使用场景(开发高频)
- 三、使用方法(分场景示例)
-
- [3.1 基础:使用系统预定义字符集(优先选择)](#3.1 基础:使用系统预定义字符集(优先选择))
- [3.2 进阶:自定义字符集(NSMutableCharacterSet)](#3.2 进阶:自定义字符集(NSMutableCharacterSet))
- [3.3 高级:按字符集拆分字符串](#3.3 高级:按字符集拆分字符串)
- 四、注意事项(避坑核心)
- 总结
NSString
一、字符串查询/判断(最常用)
| 方法 |
作用 |
示例 |
length |
获取字符串长度(UTF-16 编码的字符数) |
NSString *str = @"Hello"; NSInteger len = str.length; // 5 |
isEqualToString: |
判断两个字符串内容是否完全相等(区分大小写) |
BOOL isSame = [@"abc" isEqualToString:@"ABC"]; // NO |
hasPrefix: |
判断字符串是否以指定前缀开头 |
BOOL isHttp = [@"https://xxx" hasPrefix:@"http"]; // YES |
hasSuffix: |
判断字符串是否以指定后缀结尾 |
BOOL isTxt = [@"test.txt" hasSuffix:@".txt"]; // YES |
containsString: |
判断字符串是否包含指定子串(iOS 8+) |
BOOL hasWorld = [@"Hello World" containsString:@"World"]; // YES |
rangeOfString: |
获取子串在字符串中的位置(返回 NSRange,未找到则 location=NSNotFound) |
NSRange range = [@"Hello" rangeOfString:@"ll"]; // {2,2}(位置2,长度2) |
二、字符串截取/拆分(高频)
| 方法 |
作用 |
示例 |
substringFromIndex: |
从指定索引开始截取到末尾 |
NSString *sub = [@"HelloWorld" substringFromIndex:5]; // "World" |
substringToIndex: |
从开头截取到指定索引(不包含该索引) |
NSString *sub = [@"HelloWorld" substringToIndex:5]; // "Hello" |
substringWithRange: |
按指定范围(NSRange)截取子串 |
NSString *sub = [@"HelloWorld" substringWithRange:NSMakeRange(2,3)]; // "llo" |
componentsSeparatedByString: |
按指定分隔符拆分字符串为数组 |
NSArray *arr = [@"a,b,c" componentsSeparatedByString:@","]; // @[@"a",@"b",@"c"] |
componentsSeparatedByCharactersInSet: |
按指定字符集拆分(比如按空格/换行拆分) |
NSArray *arr = [@"a b\nc" componentsSeparatedByCharactersInSet:[NSCharacterSet whitespaceAndNewlineCharacterSet]]; // @[@"a",@"b",@"c"] |
三、字符串修改/转换(常用)B
| 方法 |
作用 |
示例 |
uppercaseString |
转为全大写 |
NSString *upper = [@"hello" uppercaseString]; // "HELLO" |
lowercaseString |
转为全小写 |
NSString *lower = [@"HELLO" lowercaseString]; // "hello" |
capitalizedString |
首字母大写(每个单词首字母) |
NSString *cap = [@"hello world" capitalizedString]; // "Hello World" |
stringByTrimmingCharactersInSet: |
去除首尾指定字符(常用:去除空格/换行) |
NSString *trimmed = [@" hello \n" stringByTrimmingCharactersInSet:[NSCharacterSet whitespaceAndNewlineCharacterSet]]; // "hello" |
stringByReplacingOccurrencesOfString:withString: |
替换所有指定子串 |
NSString *newStr = [@"a-b-c" stringByReplacingOccurrencesOfString:@"-" withString:@"_"]; // "a_b_c" |
stringByReplacingCharactersInRange:withString: |
按范围替换子串 |
NSString *newStr = [@"Hello" stringByReplacingCharactersInRange:NSMakeRange(0,1) withString:@"h"]; // "hello" |
四、路径/URL专用方法(iOS/macOS 开发核心)
| 方法 |
作用 |
示例 |
stringByAppendingPathComponent: |
拼接路径片段,自动修正 / 分隔符 |
NSString *path = [@"/Documents" stringByAppendingPathComponent:@"test.txt"]; // "/Documents/test.txt" |
lastPathComponent |
获取路径最后一部分(文件名/文件夹名) |
NSString *name = [@"/Documents/test.txt" lastPathComponent]; // "test.txt" |
stringByDeletingLastPathComponent |
删除路径最后一部分(返回上级目录) |
NSString *dir = [@"/Documents/test.txt" stringByDeletingLastPathComponent]; // "/Documents" |
pathExtension |
获取文件扩展名 |
NSString *ext = [@"test.txt" pathExtension]; // "txt" |
stringByDeletingPathExtension |
删除文件扩展名 |
NSString *name = [@"test.txt" stringByDeletingPathExtension]; // "test" |
stringByAddingPercentEncodingWithAllowedCharacters: |
URL编码(iOS 9+) |
NSString *encoded = [@"张三" stringByAddingPercentEncodingWithAllowedCharacters:[NSCharacterSet URLQueryAllowedCharacterSet]]; |
五、数据转换(跨类型处理)
| 方法 |
作用 |
示例 |
integerValue/floatValue/doubleValue |
转为对应数值类型 |
NSInteger num = [@"123" integerValue]; // 123 |
boolValue |
转为布尔值("YES"/"1"→YES,"NO"/"0"→NO) |
BOOL b = [@"YES" boolValue]; // YES |
dataUsingEncoding: |
转为 NSData(指定编码,如 UTF-8) |
NSData *data = [@"hello" dataUsingEncoding:NSUTF8StringEncoding]; |
initWithData:encoding: |
从 NSData 初始化字符串 |
NSString *str = [[NSString alloc] initWithData:data encoding:NSUTF8StringEncoding]; |
补充:之前的「三个拼接方法对比表」(Markdown 版)
| 方法 |
核心定位 |
核心行为 |
性能 |
关键特性 |
stringByAppendingString: |
纯字符串拼接工具 |
把第二个字符串原样拼接 到第一个末尾,无任何字符处理(比如不修正 /、不解析占位符) |
最高(仅简单字符串拼接,无额外逻辑) |
极简、无额外处理,仅做"字符拼接" |
stringByAppendingPathComponent: |
文件路径专用拼接工具 |
拼接路径片段,自动修正路径分隔符 / : 1. 原路径末尾有 / → 自动去重 2. 原路径无 / → 自动补充 3. 适配 iOS/macOS 路径规范 |
中等(多了分隔符校验逻辑) |
专为文件路径设计,保证路径合法性 |
stringWithFormat: |
格式化字符串生成工具 |
解析带占位符(%@/%d 等)的模板字符串,将参数按格式填充生成新字符串 |
最低(需解析占位符、类型转换) |
支持多参数、多类型(字符串/数字等)拼接,核心是"格式化" |
NSRange
一、NSRange 核心定义
NSRange 是 Foundation 框架提供的结构体(非类/方法),专门用于描述"起始位置 + 长度"的范围,是处理字符串、数组等有序集合的基础工具。
| 核心信息 |
具体说明 |
| 结构体声明 |
typedef struct _NSRange { NSUInteger location; // 起始位置(索引,从 0 开始) NSUInteger length; // 范围长度(包含的元素个数)} NSRange; |
| 关键常量 |
NSNotFound:表示"未找到"(等价于 NSUIntegerMax,赋值给 location 时代表范围无效) |
| 构造方式 |
1. 直接赋值:NSRange range = {2, 3};(位置2,长度3) 2. 推荐方法:NSRange range = NSMakeRange(2, 3);(更易读) |
二、NSRange 核心使用场景
NSRange 主要用于有序集合(字符串/数组) 的"查找、截取、替换"操作,是 Objective-C 开发中高频使用的工具,核心场景如下:
| 使用场景 |
作用说明 |
关联类/方法 |
| 字符串查找 |
获取子串在父字符串中的位置和长度 |
NSString 的 rangeOfString: 方法 |
| 字符串截取 |
按指定范围截取子串 |
NSString 的 substringWithRange: 方法 |
| 字符串替换 |
按指定范围替换部分字符串 |
NSString 的 stringByReplacingCharactersInRange:withString: 方法 |
| 数组操作 |
截取数组的指定范围元素 |
NSArray 的 subarrayWithRange: 方法 |
| 文本控件操作 |
定位文本输入框的选中范围 |
UITextField/UITextView 的 selectedRange 属性 |
三、NSRange 与其他类型的转换
NSRange 是结构体,无法直接和字符串/数字转换,但可通过工具方法实现"范围 ↔ 可读字符串"的转换,方便调试和日志输出:
| 转换方向 |
方法/示例 |
说明 |
| NSRange → NSString(调试用) |
NSString *rangeStr = NSStringFromRange(range); |
将范围转为字符串(如 {2,3} → @"{2,3}") |
| NSString → NSRange |
NSRange range = NSRangeFromString(@"{2,3}"); |
将字符串转回 NSRange(仅用于调试,生产环境慎用) |
| NSRange ↔ 索引区间(手动计算) |
示例: // 已知结束索引,计算 NSRange NSUInteger start = 2; NSUInteger end = 5; NSRange range = NSMakeRange(start, end - start); // {2,3} |
实际开发中常需通过"起始索引+结束索引"计算范围 |
四、NSRange 实战使用示例
示例1:字符串查找(最常用)
Objective-C
复制代码
// 查找子串位置
NSString *parentStr = @"Hello World";
NSRange range = [parentStr rangeOfString:@"World"];
// 判断是否找到
if (range.location != NSNotFound) {
NSLog(@"子串位置:%ld,长度:%ld", range.location, range.length); // 输出:6,5
// 转为字符串方便调试
NSString *rangeStr = NSStringFromRange(range);
NSLog(@"范围字符串:%@", rangeStr); // 输出:{6,5}
} else {
NSLog(@"未找到子串");
}
示例2:字符串截取
Objective-C
复制代码
NSString *parentStr = @"Hello World";
// 截取 "llo"(位置2,长度3)
NSRange range = NSMakeRange(2, 3);
NSString *subStr = [parentStr substringWithRange:range];
NSLog(@"截取结果:%@", subStr); // 输出:llo
示例3:字符串替换
Objective-C
复制代码
NSString *parentStr = @"Hello World";
// 将 "World" 替换为 "iOS"
NSRange range = [parentStr rangeOfString:@"World"];
if (range.location != NSNotFound) {
NSString *newStr = [parentStr stringByReplacingCharactersInRange:range withString:@"iOS"];
NSLog(@"替换结果:%@", newStr); // 输出:Hello iOS
}
示例4:数组范围操作
Objective-C
复制代码
NSArray *array = @[@"a", @"b", @"c", @"d", @"e"];
// 截取索引1-3的元素(位置1,长度3)
NSRange range = NSMakeRange(1, 3);
NSArray *subArray = [array subarrayWithRange:range];
NSLog(@"子数组:%@", subArray); // 输出:(b, c, d)
示例5:处理"未找到"场景
Objective-C
复制代码
NSString *parentStr = @"Hello World";
NSRange range = [parentStr rangeOfString:@"Android"];
if (range.location == NSNotFound) {
NSLog(@"未找到子串 Android");
}
五、NSRange 常见坑点
| 坑点 |
避坑方法 |
| 索引越界 |
使用前检查 location 是否小于集合长度,location + length 是否超过集合长度 |
| 混淆"结束索引"和"长度" |
记住:length = 结束索引 - 起始索引,而非直接用结束索引作为 length |
| 忽略 NSNotFound 判断 |
所有通过 rangeOfString: 获取的 NSRange,必须先判断 location != NSNotFound 再使用 |
总结
NSRange 是描述"起始位置+长度"的结构体,核心用于字符串/数组的查找、截取、替换操作;
- 构造 NSRange 优先用
NSMakeRange(),判断是否找到需检查 location != NSNotFound;
- 开发中常需手动计算范围(长度=结束索引-起始索引),避免索引越界和长度错误;
NSStringFromRange()/NSRangeFromString() 仅用于调试,生产环境慎用。
你希望我把 NSCharacterSet 的核心知识点(定义、使用场景、使用方法、注意事项)整理成结构化、易理解的 Markdown 内容,方便你快速掌握和查阅,对吧?NSCharacterSet 是 Objective-C 中处理字符过滤/校验/拆分的核心工具,下面我按「核心定义→使用场景→使用方法→注意事项」的逻辑,用清晰的表格+示例呈现:
NSCharacterSet
系统预定义 NSCharacterSet 字符对照表
| 类属性 |
包含的字符类型/范围 |
controlCharacterSet |
ASCII 控制字符(0x00~0x1F、0x7F):换行\n、制表符\t、退格\b、空字符\0等不可打印字符 |
whitespaceCharacterSet |
水平空白字符:空格( )、制表符(\t)、垂直制表符等(不含换行/回车) |
whitespaceAndNewlineCharacterSet |
水平空白字符 + 换行符(\n)、回车符(\r) |
decimalDigitCharacterSet |
十进制数字:0-9(Unicode 0x30~0x39) |
letterCharacterSet |
所有字母(大小写):A-Z、a-z + 多语言字母(é、ü、ñ 等) |
lowercaseLetterCharacterSet |
小写字母:a-z + 多语言小写字母(è、ü 等) |
uppercaseLetterCharacterSet |
大写字母:A-Z + 多语言大写字母(È、Ü 等) |
nonBaseCharacterSet |
附加符号:重音符号(̀、́)、波浪符(̃)等(需和基础字符组合显示) |
alphanumericCharacterSet |
字母(全语言) + 十进制数字(0-9) |
decomposableCharacterSet |
可分解组合字符:é(e+重音)、ñ(n+~)、æ(a+e)等 |
illegalCharacterSet |
系统非法字符:不可打印 Unicode 字符、文件路径非法字符、未定义编码字符 |
punctuationCharacterSet |
全类型标点:逗号、句号、问号、感叹号、破折号、括号、引号、顿号、逗号等 |
capitalizedLetterCharacterSet |
首字母大写字符(Title Case):如 Hello 中的 H、World 中的 W |
symbolCharacterSet |
各类符号:$、%、&、*、+、_、#、@、¥、%、^、& 等 |
newlineCharacterSet |
换行相关字符:换行符(\n)、回车符(\r)、\r\n 组合 |
一、NSCharacterSet 核心定义
NSCharacterSet(不可变)/NSMutableCharacterSet(可变)是 Foundation 框架中用于描述一组字符规则的集合类,核心作用是快速过滤、拆分、校验字符串中的字符,替代手动遍历字符判断,效率更高、代码更简洁。
| 核心信息 |
具体说明 |
| 类特性 |
- NSCharacterSet:不可变,创建后无法修改包含的字符规则 - NSMutableCharacterSet:可变子类,可动态添加/删除字符规则 |
| 底层逻辑 |
并非存储具体字符列表,而是通过"字符范围/规则"描述字符集合,判断字符是否属于集合时效率为 O(1) |
| 核心价值 |
避免手动遍历字符串判断字符类型(如"是否是数字""是否是空格"),简化代码且性能更优 |
二、核心使用场景(开发高频)
| 使用场景 |
具体说明 |
关联 NSString 方法 |
| 去除字符串首尾指定字符 |
过滤开头/结尾的空格、换行、特殊符号(最常用) |
stringByTrimmingCharactersInSet: |
| 按字符规则拆分字符串 |
按"任意空白/换行""任意数字"等规则拆分字符串 |
componentsSeparatedByCharactersInSet: |
| 过滤字符串中的指定字符 |
保留/删除字符串中属于某字符集的字符(如仅保留数字) |
结合 componentsSeparatedByCharactersInSet: + 拼接实现 |
| 校验字符/字符串类型 |
判断字符是否是数字/字母、字符串是否仅含指定字符(如用户名校验) |
characterIsMember: |
| URL 编码/解码 |
过滤 URL 中非法字符,仅保留允许的字符 |
stringByAddingPercentEncodingWithAllowedCharacters: |
三、使用方法(分场景示例)
3.1 基础:使用系统预定义字符集(优先选择)
苹果内置了常用字符集,无需自定义即可直接使用,覆盖80%的开发场景:
Objective-C
复制代码
// 1. 去除字符串首尾的空格+换行(最常用)
NSString *input = @" Hello World \n\r";
NSCharacterSet *spaceSet = [NSCharacterSet whitespaceAndNewlineCharacterSet];
NSString *trimmed = [input stringByTrimmingCharactersInSet:spaceSet];
NSLog(@"处理后:%@", trimmed); // 输出:Hello World
// 2. 判断字符是否是数字
unichar ch = '8';
NSCharacterSet *digitSet = [NSCharacterSet decimalDigitCharacterSet];
BOOL isDigit = [digitSet characterIsMember:ch]; // YES
3.2 进阶:自定义字符集(NSMutableCharacterSet)
需过滤特殊字符(如仅允许字母/数字/中文)时,用可变字符集自定义:
Objective-C
复制代码
// 需求:过滤昵称中的特殊符号,仅保留字母、数字、中文、下划线
NSString *nickname = @"张三_#123$";
// 1. 创建可变字符集,初始包含字母+数字
NSMutableCharacterSet *allowedSet = [NSMutableCharacterSet alphanumericCharacterSet];
// 2. 添加中文(Unicode 范围:0x4E00 ~ 0x9FFF)
[allowedSet addCharactersInRange:NSMakeRange(0x4E00, 0x9FFF - 0x4E00 + 1)];
// 3. 添加下划线
[allowedSet addCharactersInString:@"_"];
// 4. 获取"不允许的字符集"(反集)
NSCharacterSet *forbiddenSet = [allowedSet invertedSet];
// 5. 拆分并拼接,过滤不允许的字符
NSString *cleanNickname = [[nickname componentsSeparatedByCharactersInSet:forbiddenSet] componentsJoinedByString:@""];
NSLog(@"清理后:%@", cleanNickname); // 输出:张三_123
3.3 高级:按字符集拆分字符串
Objective-C
复制代码
// 需求:拆分包含空格、制表符、换行的文本
NSString *text = @"a b\tc\nd";
NSCharacterSet *splitSet = [NSCharacterSet whitespaceCharacterSet];
// 按任意空白字符拆分
NSArray *arr = [text componentsSeparatedByCharactersInSet:splitSet];
// 过滤拆分后的空字符串(避免出现@""元素)
arr = [arr filteredArrayUsingPredicate:[NSPredicate predicateWithFormat:@"SELF != ''"]];
NSLog(@"拆分结果:%@", arr); // 输出:(a, b, c, d)
四、注意事项(避坑核心)
| 注意点 |
具体说明 |
避坑方法 |
| 混淆空白字符集 |
whitespaceCharacterSet 仅包含空格/制表符,whitespaceAndNewlineCharacterSet 包含空格+换行,去除换行需用后者 |
去除首尾空白+换行时,优先用 whitespaceAndNewlineCharacterSet |
| 中文字符集范围错误 |
中文 Unicode 范围是 0x4E00 ~ 0x9FFF,计算长度需 0x9FFF - 0x4E00 + 1 |
自定义中文字符集时,严格按上述范围添加 |
| 拆分字符串后出现空元素 |
按字符集拆分时,连续分隔符会生成空字符串 |
拆分后用谓词过滤空字符串(SELF != '') |
直接用 characterIsMember: 判断多字符字符串 |
characterIsMember: 仅接收单个 unichar 字符,无法直接判断字符串 |
遍历字符串的每个字符,逐一调用 characterIsMember: |
| 误用不可变字符集修改 |
NSCharacterSet 不可变,调用 addCharactersInString: 会编译报错 |
需修改字符集时,使用 NSMutableCharacterSet |
| URL 编码字符集错误 |
手动自定义 URL 允许字符集易出错,优先用系统预定义的 URLQueryAllowedCharacterSet |
避免手动拼接 URL 允许字符,使用 [NSCharacterSet URLQueryAllowedCharacterSet] |
总结
- 核心定位 :
NSCharacterSet 是字符过滤/校验的高效工具,优先使用系统预定义字符集,减少自定义成本;
- 高频用法 :
whitespaceAndNewlineCharacterSet + stringByTrimmingCharactersInSet: 去除首尾空白,是开发中最常用的组合;
- 关键技巧 :通过
invertedSet 获取字符集反集,可快速实现"过滤非指定字符";
- 避坑核心:区分空白字符集、正确设置中文字符 Unicode 范围、拆分后过滤空元素。