在 Object-c中,字符串处理通常使用NSString,NSMutableString这两个类,前者用于定长字符串,后者用于可变长度字符串的操 作。尽量其提供的方法很丰富,但一用起来后就让人感到很难受,比如其超长的方法名称(如 stringByReplacingPercentEscapesUsingEncoding),再加上嵌套“[]”式的调用方式,让人很快就会产生" []"匹配综合症。
即使X Code提供了自动配对“[]”号的功能,但一阅读起源代码后依旧让人心生厌恶。给人一种“强迫打字综合症”的感觉。所以我在NSMutableString基础上用C++进行了封装,特别是对于一些常用方法的使用,在使用时会非常方便,与C#没太大差别。
首先看一下String类的源码(说明:因为C++中有std::string这个类,为了与其区别,这里使用了首字母大写)。
- #import "RegexKitLite.h"
- #define RELEASE_SAFELY(__POINTER) { [__POINTER release]; __POINTER = nil; }
- class String {
- private:
- NSMutableString *temp;
- static inline NSMutableString* ToMutableString(NSString *str){
- return [[NSMutableString stringWithString:(NSString *)str] autorelease];
- }
- public :
- String(){
- temp = ToMutableString(@"");
- }
- String(NSString *str){
- temp = ToMutableString(str);
- }
- String(int value){
- temp = ToMutableString([NSString stringWithFormat:@"%d", value]);
- }
- String(float value){
- temp = ToMutableString([NSString stringWithFormat:@"%f", value]);
- }
- String(std::string str){
- temp = ToMutableString(toNSString(str));
- }
- String(const char* str){
- temp = ToMutableString(toNSString(str));
- }
- ~String(){
- RELEASE_SAFELY(temp);
- }
- NSString * toString(){
- return temp;
- }
- const std::string toStdString(){
- return [temp UTF8String];
- }
- NSString * toLower(){
- return [temp lowercaseString];
- }
- NSString* toUpper(){
- return [temp uppercaseString];
- }
- int length(){
- return temp.length;
- }
- bool contains(NSString *search){
- return [temp rangeOfString:search].location != NSNotFound;
- }
- //不考虑大小写
- static BOOL stringEquals(NSString* str1, NSString* str2)
- {
- if ( str1 == nil || str2 == nil ) {
- return NO;
- }
- return [str1 compare:str2 options:NSCaseInsensitiveSearch] == NSOrderedSame;
- }
- //区分大小写
- static BOOL caseEquals(NSString* str1, NSString* str2)
- {
- return (str1 == nil || str2 == nil) ? NO : [str1 isEqualToString:str2];
- }
- bool operator==( NSString *str)
- {
- return caseEquals(this->toString(), str);
- }
- bool operator==( String *str)
- {
- return caseEquals(this->toString(), str->toString());
- }
- //区分大小写
- BOOL startWith(NSString *prefix){
- if ( temp != nil && prefix != nil ){
- if ( prefix.length > temp.length ) {
- return NO;
- }
- if ([temp hasPrefix:prefix]){
- return YES;
- }
- }
- return NO;
- }
- //区分大小写
- BOOL endWith(NSString* suffix){
- if ( temp != nil && suffix != nil ){
- if ( [suffix length] > [temp length] ) {
- return NO;
- }
- if ([temp hasSuffix:suffix]){
- return YES;
- }
- }
- return NO;
- }
- String& operator=( NSString *str)
- {
- temp = ToMutableString(str);
- return (*this);
- }
- String& operator=( std::string str)
- {
- temp = ToMutableString(toNSString(str));
- return (*this);
- }
- String& operator=( Json::Value value)
- {
- temp = ToMutableString(toNSString(value.asString()));
- return (*this);
- }
- //不区别大小写
- BOOL isURL(){
- if ( [temp length] > 6 ) {
- NSString* prefix = [temp substringToIndex:6];
- if (stringEquals(prefix, @"http:/") || stringEquals(prefix, @"https:") ) {
- return YES;
- } else if (stringEquals(prefix, @"local:")){
- return YES;
- }
- }
- if (startWith(@"/")){
- return YES;
- }
- return NO;
- }
- int toInt(){
- return [temp intValue];
- }
- int toFloat(){
- return [temp floatValue];
- }
- NSDate* toDate(NSString* fmt){
- return stringToDate(temp, fmt);
- }
- NSArray* split(NSString *schar){
- return [temp componentsSeparatedByString:schar];
- }
- String& trim(){
- temp = ToMutableString([temp stringByTrimmingCharactersInSet: [NSCharacterSet whitespaceAndNewlineCharacterSet]]);
- return (*this);
- }
- String& append(NSString *appstr){
- [temp appendString:appstr];
- return *this;
- }
- BOOL isEmpty(){
- return temp == nil || [temp length] == 0;
- }
- String& appendFormat(NSString* formatStr, ...){
- va_list arglist;
- va_start(arglist, formatStr);
- id statement = [[NSString alloc] initWithFormat:formatStr arguments:arglist];
- va_end(arglist);
- [temp appendString:statement];
- [statement release];
- return *this;
- }
- String& replace(NSString *oldStr, NSString *newStr){
- [temp replaceOccurrencesOfString:oldStr
- withString:newStr
- options:0 range:NSMakeRange(0, [temp length])];
- return *this;
- }
- String& regexReplace(NSString *regex, NSString *newStr){
- NSString *tempstr = temp;
- temp = ToMutableString([tempstr stringByReplacingOccurrencesOfRegex:regex withString:newStr]);
- return *this;
- }
- NSArray* regexMatchs(NSString *regex){
- return [temp componentsMatchedByRegex:regex];
- }
- NSArray* regexMatchs(NSString *regex, int capture){
- return [temp componentsMatchedByRegex:regex capture:capture];
- }
- BOOL regexIsMatch(NSString *regex){
- return [temp isMatchedByRegex:regex];
- }
- NSString * encodeUrl(){
- NSString *resultStr = temp;
- CFStringRef originalString = (CFStringRef) temp;
- CFStringRef leaveUnescaped = CFSTR(" ");
- CFStringRef forceEscaped = CFSTR("!*'();:@&=+$,/?%#[]");
- CFStringRef escapedStr;
- escapedStr = CFURLCreateStringByAddingPercentEscapes(kCFAllocatorDefault,
- originalString,
- leaveUnescaped,
- forceEscaped,
- kCFStringEncodingUTF8);
- if(escapedStr)
- {
- NSMutableString *mutableStr = [NSMutableString stringWithString:(NSString *)escapedStr];
- CFRelease(escapedStr);
- if (!mutableStr || [mutableStr isKindOfClass:[NSNull class]] || mutableStr.length <= 0) {
- return resultStr;
- }
- // replace spaces with plusses
- [mutableStr replaceOccurrencesOfString:@" "
- withString:@"%20"
- options:0
- range:NSMakeRange(0, [mutableStr length])];
- resultStr = mutableStr;
- }
- return resultStr;
- }
- NSString * decodeUrl(){
- return [temp stringByReplacingPercentEscapesUsingEncoding:NSUTF8StringEncoding];
- }
- NSString * toGBK(){
- NSStringEncoding enc = CFStringConvertEncodingToNSStringEncoding(kCFStringEncodingGB_18030_2000);
- NSData *data = [temp dataUsingEncoding:NSUTF8StringEncoding];
- return [[[NSString alloc] initWithData:data encoding:enc] autorelease];
- }
- NSString * toUTF8(){
- return [DZUtils urlEncode:temp stringEncode:NSUTF8StringEncoding];
- }
- NSData * toNSData(){
- return [temp dataUsingEncoding:NSUTF8StringEncoding];
- }
- NSString* subString(int start/*start from 0*/, int count){
- if(start + count <= temp.length)
- return [temp substringWithRange:NSMakeRange(start, count)];
- return nil;
- }
- NSString* subString(int count){
- if(count <= temp.length)
- return [temp substringToIndex: count];
- return nil;
- }
- static NSDate* stringToDate(NSString * string, NSString* fmt){
- NSDateFormatter *formatter = [[NSDateFormatter alloc] init];
- [formatter setTimeZone:[NSTimeZone defaultTimeZone]];
- NSString* format = fmt == nil ? @"yyyy-MM-dd'T'HH:mm:ss'Z'" : fmt;
- [formatter setDateFormat:format];
- NSDate *date = [formatter dateFromString:string];
- [formatter release];
- return date;
- }
- static NSString* dateToString(NSDate* date, NSString* fmt){
- NSDateFormatter *formatter = [[NSDateFormatter alloc] init];
- [formatter setTimeZone:[NSTimeZone defaultTimeZone]];
- NSString* format = fmt == nil ? @"yyyy-MM-dd'T'HH:mm:ss'Z'" : fmt;
- [formatter setDateFormat:format];
- NSString* dateStr = [formatter stringFromDate:date];
- [formatter release];
- return dateStr;
- }
- static NSString* format(NSString* formatStr, ...){
- va_list arglist;
- va_start(arglist, formatStr);
- id statement = [[[NSString alloc] initWithFormat:formatStr arguments:arglist] autorelease];
- va_end(arglist);
- return statement;
- }
- static NSString* toNSString(std::string str){
- return toNSString(str.c_str());
- }
- static NSString* toNSString(const char* str){
- return [NSString stringWithUTF8String:str];
- }
- static NSString* toNSString(Json::Value value){
- return toNSString(value.asString());
- }
- static String Create(Json::Value value){
- String str(toNSString(value));
- return str;
- }
- };
从源码中可以 看出,为了支持正则式,这里使用了RegexKitLite库,网上有不少网友问为什么使用这个H文件时,如果.m文件改成支持C++的.mm后缀之后, 会造编译错误('capture Count'was not declared in this scope),导致程序运行不起来。而网友的解决方法就是不使用.MM后缀文件。但经过分析我发现是BLOCK块语法导致编译错误的,在经过不断尝试之 后,发现只要修改该头文件中的如下宏定义,就可以将该头文件包含在MM文件中了:
#if !defined(RKL_BLOCKS) && defined(NS_BLOCKS_AVAILABLE) && (NS_BLOCKS_AVAILABLE == 1)
#define RKL_BLOCKS 1 //此处需要从1改为0
#endif
另外上面的String类的实现中,方法名称主要是参考C#中的字符串处理类的名称。所以可以很方法的使用。
NSString *test1 = @"imgOnLoad";
NSString *test2 = @" trim test ";
String s(test1);
test1 = s.trim().toUpper();
比如下面将字符串转小写并TRIM掉首尾空格:
NSString *test1 = @"imgOnLoad";
NSString *test2 = @" trim test ";
String s(test1);
test1 = s.trim().toUpper();
判断字符串是否以指定内容开始或结束时:
BOOL result = s.startWith(@"imga");
result = s.endWith(@"load");
也可以直接将NSString*赋值给String实例
s = test2;
获取字符串长度
int i = s.length();
字符串格式化及绑定:
String s1(123);
s1 = String::format(@"%@daizhj%@", @"diaoyudao", @"123");
String ss = String::format(@"http://%@www.sina.com.cn%@/ http", @"1", @"hello");
字符串替换:
test2 = s.replace(@"http", @"ddz").replace(@"sina", @"163").toString();
以及在C#开发中学中的StringBuilder类的appendFormat方法,这里也有相关方法对应:
test2 = s.appendFormat(@"%@daizhj%@", @"diaoyudao", @"123")
.appendFormat(@"%@fffffff%@", @"dddddd", @"123")
.appendFormat(@"%@aaaa%@", @"vvvvvv", @"123").toString();
截取子串:
test2 = s.subString(2, 10);
test2 = s.subString(10);
查找字符是否存在:
BOOL search = s.contains(@"dadddd");
除此以外,还有正则替换查找,url地址的编解码,以及String对象转换成其它不同类型如date, int, float等。