http://blog.csdn.net/phunxm/article/details/46954233
上一篇梳理了NSArray&NSMutableArray常用操作,这次来梳理一下Objective-C中每天都要用到的字符串处理类——NSString。
Objective-C中的NSString/NSMutableString类似MFC中的CString,封装了字符串的日常基本操作。
1.创建初始化(Initialization&Creation)
1.1 常量字符串(literal string)
NSString* constString = @"Hello, World!"; // 此处使用了字面量语法,否则需要使用alloc initWithUTF8String或stringWithUTF8String来从双引号的C String初始化NSString对象
变量constString并不是真正包含一个字符串对象,而指向内存中字符串对象的指针(地址),我们称之为对象标识符。
以下示例中,字面量@“Hello, World!”存储在文字常量区。指针constString1和constString2都指向它,它们在编译时生成的真实类型是NSConstantString(继承关系链——:NSSimpleCString:NSString)。
Objective-C里没有包或者命名空间,靠前缀来区分,NS是“NeXTSTEP”的缩写。CF是“CoreFoundation”的缩写。CFString可以看做是NSString的C底层实现。
Foundation库(Foundation.framework/Foundation.h)是有Cocoa框架提供的基本数据管理和服务功能的Objective-C接口,而Core Foundation库 (CoreFoundation.framework/CoreFoundation.h) 则是Cocoa底层实现,提供了C语言层面的接口。
以下介绍不可变字符串两种初始化创建方法。
After an immutable string has been initialized in the following way, it cannot be modified.
1.2 Initializing an String(NS_DESIGNATED_INITIALIZER)
比较常用的有以下几个:
// 从UTF8 C String初始化NSString对象
- (instancetype)initWithUTF8String:(constchar *)nullTerminatedCString;
// 从C String初始化NSString对象,指定编码格式(例如NSUTF8StringEncoding)。
- (instancetype)initWithCString:(constchar *)nullTerminatedCString encoding:(NSStringEncoding)encoding;
// 从C Buffer指定编码格式初始化NSString对象
- (instancetype)initWithBytes:(constvoid *)bytes length:(NSUInteger)len encoding:(NSStringEncoding)encoding;
// 可变参格式化初始化NSString对象
- (instancetype)initWithFormat:(NSString *)format, ...NS_FORMAT_FUNCTION(1,2);
示例:
//NSString* string = [[NSString alloc] initWithFormat:@"Hello, %s","World!"]; NSString* string = [[NSString alloc] initWithFormat:@"Hello, %@", @"World!"]; NSLog(@"string= %@", string);
关于格式化规范,参考String Format Specifiers。
- %@:OC对象描述(description)。
- %d/%D:带符号32位整数(int),NSInteger:%ld,size_t:%zd。
- %u/%U:无符号32位整数(unsigned int),NSUInteger:%lu。
- %o/%O:无符号32位整数(unsigned int)的八进制格式。
- %x/%X:无符号32位整数(unsigned int)的十六进制格式。
- %c:8位无符号字符(unsigned char)。如果非ASCII码则以八进制“\\ddd”或十六进制“\\udddd”格式显示字符值。
- %C:16位UNICODE字符(unichar)。如果非ASCII码则以八进制“\\ddd”或十六进制“\\udddd”格式显示字符值。
- %f:64位浮点数(double)
1.3 Creating an String(autorelease)
// 创建一个字符串独享,其值为空 + (instancetype)string;
示例:
NSString* constString = @""; NSString* string = [NSString string]; BOOL bPointerEqual = constString==string; // NO BOOL bContentEqualTo = [constString isEqualTo:string]; // YES BOOLbEqualToString = [constString isEqualToString:string]; // YES
以下是一些便利构造方法:
// initWithString对应的类方法 + (instancetype)stringWithString:(NSString *)string; // initWithCString:encoding对应的类方法 + (instancetype)stringWithCString:(const charchar *)cString encoding:(NSStringEncoding)enc; // initWithCharacters:length: 对应的类方法 + (instancetype)stringWithCharacters:(const unichar *)characters length:(NSUInteger)length; // initWithUTF8String对应的类方法 + (instancetype)stringWithUTF8String:(const charchar *)nullTerminatedCString; // initWithFormat对应的类方法 + (instancetype)stringWithFormat:(NSString *)format, ... NS_FORMAT_FUNCTION(1,2); + (instancetype)localizedStringWithFormat:(NSString *)format, ... NS_FORMAT_FUNCTION(1,2);
比较常用的有以下几个:
// initWithCString:encoding对应的类方法
+ (instancetype)stringWithCString:(constchar *)cString encoding:(NSStringEncoding)enc;
// initWithUTF8String对应的类方法
+ (instancetype)stringWithUTF8String:(constchar *)nullTerminatedCString;
// initWithFormat对应的类方法
+ (instancetype)stringWithFormat:(NSString *)format, ...NS_FORMAT_FUNCTION(1,2);
2.访问字符串(Querying)
2.1 字符串长度(字符数组大小)
// Thenumber of Unicode characters in the receiver. @property (readonly) NSUInteger length;
示例:
NSString* constString1 = nil; NSString* constString2 = @""; NSString* constString3 = @"Hello, World!"; NSString* constString4 = @"哈喽,世界!"; // 汉字+半角标点混合 NSLog(@"constString1[size,length] = [%zd, %zd]", sizeof(constString1),constString1.length); // [8,0] NSLog(@"constString2[size,length] = [%zd, %zd]", sizeof(constString2),constString2.length); // [8,0] NSLog(@"constString3[size,length] = [%zd, %zd]", sizeof(constString3),constString3.length); // [8,13] NSLog(@"constString4[size,length] = [%zd, %zd]", sizeof(constString4),constString4.length); // [8,6]
以上可知string.length可用来判空:如果length为零,则表示字符串对象为nil或为不包含任何字符。
2.2 字符(字符数组元素)
// 获取指定索引位置/范围的字符(集) - (unichar)characterAtIndex:(NSUInteger)index; - (void)getCharacters:(unichar *)buffer range:(NSRange)aRange;
示例:
2.3 取C String
//Convenience to return null-terminated UTF8 representation @property (readonly) __strong const charchar *UTF8String NS_RETURNS_INNER_POINTER;
2.4 取字面值
类似cstdlib中的atoi/atol/strtol/atof。
/* convenience methods all skip initial space characters (whitespaceSet)and ignore trailing characters. <strong>NSScanner</strong> can be used for more"exact" parsing of numbers. */ @property (readonly) double doubleValue; @property (readonly) float floatValue; @property (readonly) int intValue; @property (readonly) NSInteger integerValue NS_AVAILABLE(10_5, 2_0); @property (readonly) long long longLongValue NS_AVAILABLE(10_5, 2_0); @property (readonly) BOOL boolValue NS_AVAILABLE(10_5, 2_0);
2.5 大小写转换
3.查询字符串(Finding)
3.1 定位子串(rangeOf)
// 返回查找到包含子串的范围 - (NSRange)rangeOfString:(NSString *)aString; // 返回查找到包含子串的范围,可指定查询选项(忽略大小写、逆序) - (NSRange)rangeOfString:(NSString *)aString options:(NSStringCompareOptions)mask; // 返回查找到包含子串的范围,可指定查询选项(忽略大小写、逆序),可进一步指定查找范围 - (NSRange)rangeOfString:(NSString *)aString options:(NSStringCompareOptions)mask range:(NSRange)searchRange;
3.2 取子串(subString)
// 返回从指定索引到结尾的子串 - (NSString *)substringFromIndex:(NSUInteger)from; // 返回从开头到指定索引的子串 - (NSString *)substringToIndex:(NSUInteger)to; // 返回从指定范围(开始索引+长度)界定的子串 - (NSString *)substringWithRange:(NSRange)range; // Hint: Use withrangeOfComposedCharacterSequencesForRange: to avoid breaking up composedcharacters
示例:
NSString* prefix = [constString3 substringToIndex:7]; // @"Hello, " NSString* suffix = [constString3 substringFromIndex:7]; // @"World!" NSString* substr =[constString3 substringWithRange:NSMakeRange(3,6)]; // @"lo, Wo"
3.3 是否包含子串(prefix/suffix/contains)
// 是否以指定子串开头 - (BOOL)hasPrefix:(NSString *)aString; // 是否以指定子串结尾 - (BOOL)hasSuffix:(NSString *)aString; // 是否包含子串,注意只适用于iOS8以上! - (BOOL)containsString:(NSString *)aString NS_AVAILABLE(10_10, 8_0);
示例:
BOOL bHasPrefix = [constString3 hasPrefix:@"Hello,"]; // YES BOOL bHasSuffix = [constString3 hasSuffix:@"World!"]; // YES BOOL bContain= [constString3 containsString:@"lo, Wo"]; // YES
以下为NSString扩展类别(NSStringUtilities)判断是否包含子串的适配接口:
3.4 查询字符集
/* These return the range of the first character from the set in the string, not the range of a sequence of characters. */ - (NSRange)rangeOfCharacterFromSet:(NSCharacterSet *)aSet; - (NSRange)rangeOfCharacterFromSet:(NSCharacterSet *)aSet options:(NSStringCompareOptions)mask; - (NSRange)rangeOfCharacterFromSet:(NSCharacterSet *)aSet options:(NSStringCompareOptions)mask range:(NSRange)searchRange; - (NSRange)rangeOfComposedCharacterSequenceAtIndex:(NSUInteger)index; - (NSRange)rangeOfComposedCharacterSequencesForRange:(NSRange)range NS_AVAILABLE(10_5, 2_0);
4.比较字符串(Comparing)
// 判断两个字符串内容是否相等 - (BOOL)isEqualToString:(NSString *)aString; /* In the compare: methods, the range argument specifies the subrange,rather than the whole, of the receiver to use in the comparison. The range is not applied to the search string. For example, [@"AB"compare:@"ABC" options:0 range:NSMakeRange(0,1)] compares"A" to "ABC", not "A" to "A", and will return NSOrderedAscending. */ // 比较字符串,如果相同返回NSOrderedSame;如果不相同,返回第一个不相同的字符值比较结果(NSOrderedAscending、NSOrderedDescending) - (NSComparisonResult)compare:(NSString *)string; // 比较字符串,可指定比较选项(忽略大小写、逆序、按十进制值) - (NSComparisonResult)compare:(NSString *)string options:(NSStringCompareOptions)mask; // 比较字符串,可指定比较选项(忽略大小写、逆序、按十进制值),可进一步指定查找范围 - (NSComparisonResult)compare:(NSString *)string options:(NSStringCompareOptions)mask range:(NSRange)compareRange; // 比较字符串,可指定查询选项(忽略大小写、逆序、按十进制值),可进一步指定查找范围,可进一步按照本地化比较 - (NSComparisonResult)compare:(NSString *)string options:(NSStringCompareOptions)mask range:(NSRange)compareRange locale:(id)locale; //locale arg used to be a dictionary pre-Leopard. We now accept NSLocale. Assumes the current locale if non-nil and non-NSLocale. nil continues to mean canonical compare, which doesn't depend on user's locale choice. // 相当于compare:string options:NSCaseInsensitiveSearch - (NSComparisonResult)caseInsensitiveCompare:(NSString *)string; // 按照本地化比较 - (NSComparisonResult)localizedCompare:(NSString *)string; // 以上两个版本组合 - (NSComparisonResult)localizedCaseInsensitiveCompare:(NSString *)string;
5.替换子串(Replacing)
- (NSString *)stringByReplacingOccurrencesOfString:(NSString *)target withString:(NSString *)replacement options:(NSStringCompareOptions)options range:(NSRange)searchRange NS_AVAILABLE(10_5, 2_0); /* Replace all occurrences of the target string with replacement. Invokes the above method with 0 options and range of the whole string.*/ - (NSString *)stringByReplacingOccurrencesOfString:(NSString *)target withString:(NSString *)replacement NS_AVAILABLE(10_5, 2_0); /* Replace characters in range with the specified string, returning new string.*/ - (NSString *)stringByReplacingCharactersInRange:(NSRange)range withString:(NSString *)replacement NS_AVAILABLE(10_5, 2_0);
6.衍生字符串(Deriving)
// 当前字符串追加aString生成返回一个新的NSString对象。 - (NSString *)stringByAppendingString:(NSString *)aString; - (NSString *)stringByAppendingFormat:(NSString *)format, ... NS_FORMAT_FUNCTION(1,2);
7.分解字符串(Separate & Join Components)
7.1 componentsSeparatedByString/componentsJointedByString
// NSString::componentsSeparatedByString接口按照分割字符(子串)来切分字符串:NSString->NSArray - (NSArray *)componentsSeparatedByString:(NSString *)separator; - (NSArray *)componentsSeparatedByCharactersInSet:(NSCharacterSet *)separator NS_AVAILABLE(10_5, 2_0); // NSArray::componentsJoinedByString接口将多个字符串(字符串数组)以衔接字符连接:NSArray->NSString - (NSString *)componentsJoinedByString:(NSString *)separator;
以下代码示例对典型的本地文件路径字符串按分隔符进行拆分分解,然后再按分隔符衔接复原:
NSString* originString = @"do-do-sol-sol-la-la-sol"; NSArray* separatedComponents = [originString componentsSeparatedByString:@"-"]; // 拆分 NSLog(@"separatedComponents = %@", separatedComponents); NSString* jointedString = [separatedComponents componentsJoinedByString:@"-"]; //复原 NSLog(@"jointedString = %@", jointedString);
7.2 NSPathUtilities
// 基于文件路径字符串构建资源URL,例如用于共享的URL Scheme NSURL* pdWin8VMURL = [NSURL fileURLWithPath:pdWin8VMPath]; NSLog(@"pdWin8VMURL = %@", pdWin8VMURL); // pdWin8VMURL.absoluteString = file:///Users/faner/VM/Windows%208.1.pvm/
7.3 NSURLPathUtilities
NSURLPathUtilities Demo1:iOS相册文件asset URL
NSURLPathUtilities Demo2:知乎搜索“大圣归来”的HTTP URL
// demo2:知乎搜索“大圣归来”的HTTP URL NSString* zhihuSearchHttpURLPath = @"http://www.zhihu.com:80/search?q=%E5%A4%A7%E5%9C%A3%E5%BD%92%E6%9D%A5&type=question"; // 汉字部分已经使用CFURLCreateStringByAddingPercentEscapes进行URLEncode。 NSURL* zhihuSearchHttpURL = [NSURL URLWithString:zhihuSearchHttpURLPath]; // absoluteString&relativeString NSLog(@"zhihuSearchHttpURL.absoluteString = %@", zhihuSearchHttpURL.absoluteString); NSLog(@"zhihuSearchHttpURL.relativeString = %@", zhihuSearchHttpURL.relativeString); // host&port = {www.zhihu.com, 80} NSLog(@"zhihuSearchHttpURL.host/port = {%@, %@}", zhihuSearchHttpURL.host, zhihuSearchHttpURL.port); // scheme&resourceSpecifier = [url componentsSeparatedByString:@":"] NSLog(@"zhihuSearchHttpURL.scheme = %@", zhihuSearchHttpURL.scheme); // http NSLog(@"zhihuSearchHttpURL.resourceSpecifier = %@", zhihuSearchHttpURL.resourceSpecifier); // 协议冒号(不包括)之后双斜杠开始至末尾 // path&relativePath = {/search, /search} NSLog(@"zhihuSearchHttpURL.path/relativePath = {%@, %@}", zhihuSearchHttpURL.path, zhihuSearchHttpURL.relativePath); // pathComponents = {"/","search"} NSLog(@"zhihuSearchHttpURL.pathComponents = %@", zhihuSearchHttpURL.pathComponents); // lastPathComponent = pathComponents.lastObject NSLog(@"zhihuSearchHttpURL.lastPathComponent = %@", zhihuSearchHttpURL.lastPathComponent); // fragment/query,其中query为问号之后的部分 NSLog(@"zhihuSearchHttpURL.fragment/query = {%@, %@}", zhihuSearchHttpURL.fragment, zhihuSearchHttpURL.query); // {(null), q=%E5%A4%A7%E5%9C%A3%E5%BD%92%E6%9D%A5&type=question} // parameterString(RFC 1808) NSLog(@"zhihuSearchHttpURL.parameterString = %@", zhihuSearchHttpURL.parameterString); // (null)
在处理URL时,经常要解析提取query items。主要有两种途径析取:
(1)基于分隔符‘&’和‘=’对字符串进行分解提取。
// 解析查询字符串的key-value(parseComponentsFromQueryString) NSString* queryString = zhihuSearchHttpURL.query; NSMutableDictionary *queryDict = [NSMutableDictionary dictionary]; if (queryString.length) { NSArray *kvComponents = [queryString componentsSeparatedByString:@"&"]; for (NSString *kvComponent in kvComponents) { NSString *key, *value; if ([kvComponent hasContainStr:@"="]) { NSArray* KV = [kvComponent componentsSeparatedByString:@"="]; key = KV.firstObject; value = KV.lastObject; } else { key = kvComponent; value = @""; } // 暂未考虑重名参数:k={v1,v2,...} [queryDict setObject:value forKey:key]; } } // {q = "%E5%A4%A7%E5%9C%A3%E5%BD%92%E6%9D%A5"; type = question;} NSLog(@"parseComponentsFromQueryString = %@", queryDict);
(2)基于iOS7提供的新接口,基于URLString构造NSURLComponents,自动提取queryItems(NSURLQueryItem[])。
// NS_CLASS_AVAILABLE(10_9, 7_0)提供了NSURLComponents;NS_CLASS_AVAILABLE(10_10, 8_0)进一步提供了NSURLQueryItem NSURLComponents* zhihuSearchHttpURLComponents = [NSURLComponents componentsWithString:zhihuSearchHttpURLPath]; NSLog(@"zhihuSearchHttpURLComponents.queryItems = %@", zhihuSearchHttpURLComponents.queryItems); // array of NSURLQueryItem
8.可变字符串(NSMutableString)
8.1 Initializing an String(NS_DESIGNATED_INITIALIZER)
/* In addition to these two, NSMutableString responds properly to allNSString creation methods.*/ - (NSMutableString *)initWithCapacity:(NSUInteger)capacity; + (NSMutableString *)stringWithCapacity:(NSUInteger)capacity;
8.2 set/append aString
// Replaces the characters of the receiver with those in a given string.aString must not be nil. - (void)setString:(NSString *)aString;
setString类似于对retain propery的赋值(setter)。
字符串置为空串:=@””或setString:@””;
// Adds to the end of the receiver the characters of a given string.aString must not be nil - (void)appendString:(NSString *)aString; - (void)appendFormat:(NSString *)format, ... NS_FORMAT_FUNCTION(1,2);
8.3 insert/replace
- (void)insertString:(NSString *)aString atIndex:(NSUInteger)loc; // 替换 - (void)replaceCharactersInRange:(NSRange)range withString:(NSString *)aString; - (NSUInteger)replaceOccurrencesOfString:(NSString *)target withString:(NSString *)replacement options:(NSStringCompareOptions)options range:(NSRange)searchRange;
8.4 delete
// 删除指定位置、指定长度的子串 - (void)deleteCharactersInRange:(NSRange)range;
9.文件、URL与字符串
9.1 从指定文件读取内容到字符串
- (instancetype)initWithContentsOfFile:(NSString *)path encoding:(NSStringEncoding)enc error:(NSError **)error;
+ (instancetype)stringWithContentsOfFile:(NSString *)path encoding:(NSStringEncoding)enc error:(NSError **)error;
9.2 从指定url读取(下载)内容到字符串
- (instancetype)initWithContentsOfURL:(NSURL *)url encoding:(NSStringEncoding)enc error:(NSError **)error;
+ (instancetype)stringWithContentsOfURL:(NSURL *)url encoding:(NSStringEncoding)enc error:(NSError **)error;
9.3 将字符串内容写到指定url/path
/* Write to specified url or path using the specified encoding.*/ - (BOOL)writeToURL:(NSURL *)url atomically:(BOOL)useAuxiliaryFileencoding:(NSStringEncoding)encerror:(NSError **)error; - (BOOL)writeToFile:(NSString *)path atomically:(BOOL)useAuxiliaryFileencoding:(NSStringEncoding)encerror:(NSError **)error;
10.对象字符串化
10.1 NSString From CGPoint/CGSize/CGRect
NSStringFromCGPoint/CGPointFromString、NSStringFromCGSize/CGSizeFromString、 NSStringFromCGRect/CGRectFromString。
可用于对C复合类型(struct)进行OC描述(description),生成对应的字符串,方便NSLog调试输出。
10.2 NSString From Class
// 获取某个对象的具体类名,传入[obj class],相当于[obj className] FOUNDATION_EXPORT NSString *NSStringFromClass(Class aClass); // 基于类名获取类 FOUNDATION_EXPORT Class NSClassFromString(NSString *aClassName);
示例:
NSLog(@"[constString2 className] = %@", [constString2 className]); // __NSCFConstantString NSLog(@"NSStringFromClass([constString2 class]) = %@", NSStringFromClass([constString2class])); //__NSCFConstantString NSLog(@"object_getClassName(constString2) = %s", object_getClassName(constString2));// __NSCFConstantString // 返回C字符串格式的类名 const char* className = class_getName([obj class]);
类似的还有NSStringFromSelector/NSSelectorFromString,可以基于方法名称来创建SEL进而实现调用。
10.3 Class & SEL from NSString
以下代码片段中,hideAlertView接口试图dismiss当前顶层UIAlertView/UIAlertController,在iOS 7.x系统中调用半公开的_UIAlertManager::topMostAlert获取顶层UIAlertView。
- (void)hideAlertView { if (SYSTEM_VERSION < 7.0) { // iOS 7.0之前采用UIAlertView for (UIWindow* w in [UIApplication sharedApplication].windows) { for (NSObject* o in w.subviews) { if ([o isKindOfClass:[UIAlertView class]]) { UIAlertView *alert = (UIAlertView*)o; [alert dismissWithClickedButtonIndex:alert.cancelButtonIndex animated:NO]; } } } } else if (SYSTEM_VERSION < 8.0) { // iOS 8.0之前采用UIAlertView Class UIAlertManager = NSClassFromString(@"_UIAlertManager"); SEL selTopMostAlert = NSSelectorFromString(@"topMostAlert"); if ([UIAlertManager respondsToSelector:selTopMostAlert]) { UIAlertView *topMostAlert = [UIAlertManager performSelector:selTopMostAlert]; [topMostAlert dismissWithClickedButtonIndex:topMostAlert.cancelButtonIndex animated:NO]; } } else { // iOS 8.0之后采用UIAlertController UINavigationController *navCtrl = self.navigationController; if(navCtrl.presentedViewController && [navCtrl.presentedViewController isKindOfClass:[UIAlertController class]]) { [navCtrl.presentedViewController dismissViewControllerAnimated:NO completion:nil]; } } }
注意:以上代码中使用NSClassFromString、NSSelectorFromString涉及到的私有接口(_UIAlertManager::topMostAlert)可能审核不通过。打散格式化组合在一定程度上可以规避苹果的静态扫描检查。
参考:
《Objective-C研究院之NSString字符串(三)》
《Objective-C研究院之NSMutableString(四)》
《NSString &Unicode》《遍历NSString每一个字符的正确方式》
《NSString属性用copy还是用strong?》《Use copy for NSStringproperties》
《Objective-c中 isEqual ,isEqualToString , == 三者的区别》
《NSString: isEqual vs.isEqualToString》《Equality》《isEqual: vsisEqualToString:》
《How to convert anNSString to hex values》
《NSString转换成16进制》《Objective-C NSStringto Hex》
《How to convertNSString to hexadecimal string of fixed block size》
浙公网安备 33010602011771号