當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


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM