当C++遇到iOS应用开发---字符串处理
在Object-c中,字符串处理通常使用NSString,NSMutableString这两个类,前者用于定长字符串,后者用于可变长度字符串的操作。尽量其提供的方法很丰富,但一用起来后就让人感到很难受,比如其超长的方法名称(如stringByReplacingPercentEscapesUsingEncoding),再加上嵌套“[]”式的调用方式,让人很快就会产生"[]"匹配综合症。
即使xcode提供了自动配对“[]”号的功能,但一阅读起源代码后依旧让人心生厌恶。给人一种“强迫打字综合症”的感觉。所以我在NSMutableString基础上用C++进行了封装,特别是对于一些常用方法的使用,在使用时会非常方便,与C#没太大差别。
首先看一下String类的源码(说明:因为C++中有std::string这个类,为了与其区别,这里使用了首字母大写)。
#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文件中了:
#define RKL_BLOCKS 1 //此处需要从1改为0
#endif
另外上面的String类的实现中,方法名称主要是参考C#中的字符串处理类的名称。所以可以很方法的使用。
比如下面将字符串转小写并TRIM掉首尾空格:
NSString *test2 = @" trim test ";
String s(test1);
test1 = s.trim().toUpper();
判断字符串是否以指定内容开始或结束时:
result = s.endWith(@"load");
也可以直接将NSString*赋值给String实例
获取字符串长度
字符串格式化及绑定:
s1 = String::format(@"%@daizhj%@", @"diaoyudao", @"123");
String ss = String::format(@"http://%@www.sina.com.cn%@/ http", @"1", @"hello");
字符串替换:
以及在C#开发中学中的StringBuilder类的appendFormat方法,这里也有相关方法对应:
.appendFormat(@"%@fffffff%@", @"dddddd", @"123")
.appendFormat(@"%@aaaa%@", @"vvvvvv", @"123").toString();
截取子串:
test2 = s.subString(10);
查找字符是否存在:
除此以外,还有正则替换查找,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