当C++遇到iOS应用开发---字符串处理

      在Object-c中,字符串处理通常使用NSString,NSMutableString这两个类,前者用于定长字符串,后者用于可变长度字符串的操作。尽量其提供的方法很丰富,但一用起来后就让人感到很难受,比如其超长的方法名称(如stringByReplacingPercentEscapesUsingEncoding),再加上嵌套“[]”式的调用方式,让人很快就会产生"[]"匹配综合症。
      即使xcode提供了自动配对“[]”号的功能,但一阅读起源代码后依旧让人心生厌恶。给人一种“强迫打字综合症”的感觉。所以我在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后缀之后,会造编译错误('captureCount' 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#中的字符串处理类的名称。所以可以很方法的使用。

    比如下面将字符串转小写并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(210);
    test2 = s.subString(10);



    查找字符是否存在:

    BOOL search = s.contains(@"dadddd");



    除此以外,还有正则替换查找,url地址的编解码,以及String对象转换成其它不同类型如date, int, float等。
   
    String类支持Json::Value格式,而有关IOS中使用C++ json内容,我会在后面的BLOG中加以介绍。
  
    好了,今天的内容就先到这里了。

      原文链接:http://www.cnblogs.com/daizhj/archive/2012/11/06/String-cpulsplus-ios.html

     作者: daizhj, 代震军  
     微博: http://weibo.com/daizhj
     Tags:ios, c++, string

posted @ 2012-11-06 17:12  代震军  阅读(8690)  评论(2编辑  收藏  举报