一个实用的NSString分类工具 (一)—— 玩转数字

版本记录

版本号 时间
V1.0 2017.12.15

前言

NSString是我们经常使用的一个类,但是苹果的API很多用起来不是那么方便,需要根据我们特殊需求进行个性化的改变和定制,接下来,我就写一个NSString分类工具,以后在使用的时候直接调用这个分类中的方法,可以实现很多小的功能,用起来也很方便。相关代码已经上传至GitHub - 刀客传奇

计算字符串的占的宽度

很多时候,我们需要计算UILabel或者UIButton的宽度,因为里面的文字可能是从服务器返回的,所以要求这个控件的宽度也是自适应的,这就需要我们实时的计算返回的字符串占的宽度。

先看下面的代码。

//根据字符串长度获取字符串尺寸

- (CGSize)jj_textSizeWithFont:(UIFont *)font
            constrainedToSize:(CGSize)size;
//根据字符串长度获取字符串尺寸

- (CGSize)jj_textSizeWithFont:(UIFont *)font
            constrainedToSize:(CGSize)size
{
    CGSize textSize;
    
    if (CGSizeEqualToSize(size, CGSizeZero)) {
        NSDictionary *attributes = [NSDictionary dictionaryWithObject:font forKey:NSFontAttributeName];
        textSize = [self sizeWithAttributes:attributes];
        textSize = CGSizeMake(floor(size.width), floor(size.height));
    }
    else {
        NSStringDrawingOptions option = NSStringDrawingTruncatesLastVisibleLine | NSStringDrawingUsesLineFragmentOrigin | NSStringDrawingUsesFontLeading;
        
        //NSStringDrawingTruncatesLastVisibleLine如果文本内容超出指定的矩形限制,文本将被截去并在最后一个字符后加上省略号。 如果指定了NSStringDrawingUsesLineFragmentOrigin选项,则该选项被忽略 NSStringDrawingUsesFontLeading计算行高时使用行间距。(译者注:字体大小+行间距=行高)
        
        NSDictionary *attributes = [NSDictionary dictionaryWithObject:font forKey:NSFontAttributeName];
        
        CGRect rect = [self boundingRectWithSize:size options:option attributes:attributes context:nil];
        textSize = rect.size;
        
        //注意:当字符串同时存在@和&字符时,使用NSStringDrawingUsesLineFragmentOrigin时rect会变为零
        if (CGSizeEqualToSize(textSize, CGSizeZero)) {
            option = NSStringDrawingTruncatesLastVisibleLine | NSStringDrawingUsesFontLeading;
            rect = [self boundingRectWithSize:size options:option attributes:attributes context:nil];
            textSize = rect.size;
        }
    }
    return textSize;
}

下面我们就调用一下。

#import "ViewController.h"
#import "NSString+JJNSStringExt.h"

@interface ViewController ()

@end

@implementation ViewController

#pragma mark - Override Base Function

- (void)viewDidLoad
{
    [super viewDidLoad];
    
    self.view.backgroundColor = [UIColor lightGrayColor];
    
    NSString *str = @"我们是一家人";
    UIButton *button = [UIButton buttonWithType:UIButtonTypeCustom];
    [self.view addSubview:button];
    [button setTitle:str forState:UIControlStateNormal];
    button.titleLabel.font = [UIFont systemFontOfSize:17.0];
    button.backgroundColor = [UIColor blueColor];
    CGSize size = [str jj_textSizeWithFont:button.titleLabel.font constrainedToSize:CGSizeMake(MAXFLOAT, 22.0)];
    button.frame = CGRectMake(100.0, 150.0, size.width + 20.0, 30.0);
    NSLog(@"button = %@", button);
}

@end

下面看一下输出结果

2017-12-15 23:46:56.149169+0800 JJNSStringTool[1259:19762] button = <UIButton: 0x7ffa9fc07ee0; frame = (100 150; 123.938 30); opaque = NO; layer = <CALayer: 0x604000222340>>

下面看一下效果图


判断是否是手机号

先看分类方法

//是否是手机号的判定

- (BOOL)jj_isPhoneNumberWithStr:(NSString *)str;
/*
 是否是手机号的判定
 
 移动:139 138 137 136 135 134 147 188 187 184 183 182 178 159 158 157 152 151 150 1703 1705 1706 198
 联通:186 185 176 145 156 155 132 131 130 175 176 1704 1707 1708 1709 171 166
 电信:189 181 180 177 153 133 173 1700 1701 1702 199
 */

- (BOOL)jj_isPhoneNumberWithStr:(NSString *)str
{
    str = [str stringByReplacingOccurrencesOfString:@" " withString:@""];
    if (str.length != 11) {
        return NO;
    }
    else {
        
        //移动
        NSString *CM_NUM = @"^((13[4-9])|(147)|(15[0-2,7-9])|(178)|(18[2-4,7-8])|(198))\\d{8}|(170[3,5,6])\\d{7}$";
        //联通
        NSString *CU_NUM = @"^((13[0-2])|(145)|(15[5-6])|(17[5,6])|(18[5,6])|(166))\\d{8}|(170[4,7-9])\\d{7}|171[0-9]\\d{7}$";
        //电信
        NSString *CT_NUM = @"^((133)|(153)|(17[3,7])|(18[0,1,9])|(199))\\d{8}|(170[0-2])\\d{7}$";
        
        NSPredicate *pred1 = [NSPredicate predicateWithFormat:@"SELF MATCHES %@", CM_NUM];
        BOOL isMatch1 = [pred1 evaluateWithObject:str];
        NSPredicate *pred2 = [NSPredicate predicateWithFormat:@"SELF MATCHES %@", CU_NUM];
        BOOL isMatch2 = [pred2 evaluateWithObject:str];
        NSPredicate *pred3 = [NSPredicate predicateWithFormat:@"SELF MATCHES %@", CT_NUM];
        BOOL isMatch3 = [pred3 evaluateWithObject:str];
        if (isMatch1 || isMatch2 || isMatch3) {
            return YES;
        }
        else {
            return NO;
        }
    }
}

下面看调用过程

    NSString *str = @"18613546782";
    BOOL result = [str jj_isPhoneNumberWithStr:str];
    NSLog(@"result = %d", result);
    
    NSString *str1 = @"11111111111";
    BOOL result1 = [str1 jj_isPhoneNumberWithStr:str1];
    NSLog(@"result1 = %d", result1);

下面看输出结果

2017-12-16 00:21:15.543055+0800 JJNSStringTool[1675:35852] result = 1
2017-12-16 00:21:15.543518+0800 JJNSStringTool[1675:35852] result1 = 0

可见,可以实现对手机号码的判定。


身份证号码的验证

还是直接看代码

//身份证号码验证

- (BOOL)jj_isCardIdValid;
//身份证号码验证

- (BOOL)jj_isCardIdValid
{
    NSString * cardId = self;
    cardId = [cardId stringByTrimmingCharactersInSet:[NSCharacterSet whitespaceAndNewlineCharacterSet]];
    NSUInteger length =0;
    if (!cardId) {
        return NO;
    }
    else {
        length = cardId.length;
        
        if (length !=15 && length !=18) {
            return NO;
        }
    }
    // 省份代码
    NSArray *areasArray =@[@"11",@"12", @"13",@"14", @"15",@"21", @"22",@"23", @"31",@"32", @"33",@"34", @"35",@"36", @"37",@"41", @"42",@"43", @"44",@"45", @"46",@"50", @"51",@"52", @"53",@"54", @"61",@"62", @"63",@"64", @"65",@"71", @"81",@"82", @"91"];
    
    NSString *valueStart2 = [cardId substringToIndex:2];
    BOOL areaFlag =NO;
    for (NSString *areaCode in areasArray) {
        if ([areaCode isEqualToString:valueStart2]) {
            areaFlag =YES;
            break;
        }
    }
    
    if (!areaFlag) {
        return false;
    }
    
    
    NSRegularExpression *regularExpression;
    NSUInteger numberofMatch;
    
    int year =0;
    switch (length) {
        case 15:
            year = [cardId substringWithRange:NSMakeRange(6,2)].intValue +1900;
            
            if (year %4 ==0 || (year %100 ==0 && year %4 ==0)) {
                
                regularExpression = [[NSRegularExpression alloc]initWithPattern:@"^[1-9][0-9]{5}[0-9]{2}((01|03|05|07|08|10|12)(0[1-9]|[1-2][0-9]|3[0-1])|(04|06|09|11)(0[1-9]|[1-2][0-9]|30)|02(0[1-9]|[1-2][0-9]))[0-9]{3}$"
                                                                        options:NSRegularExpressionCaseInsensitive
                                                                          error:nil];//测试出生日期的合法性
            }
            else {
                regularExpression = [[NSRegularExpression alloc]initWithPattern:@"^[1-9][0-9]{5}[0-9]{2}((01|03|05|07|08|10|12)(0[1-9]|[1-2][0-9]|3[0-1])|(04|06|09|11)(0[1-9]|[1-2][0-9]|30)|02(0[1-9]|1[0-9]|2[0-8]))[0-9]{3}$"
                                                                        options:NSRegularExpressionCaseInsensitive
                                                                          error:nil];//测试出生日期的合法性
            }
            numberofMatch = [regularExpression numberOfMatchesInString:cardId
                                                               options:NSMatchingReportProgress
                                                                 range:NSMakeRange(0, cardId.length)];
            
            
            if(numberofMatch >0) {
                return YES;
            }
            else {
                return NO;
            }
        case 18:
            
            year = [cardId substringWithRange:NSMakeRange(6,4)].intValue;
            if (year %4 ==0 || (year %100 ==0 && year %4 ==0)) {
                
                regularExpression = [[NSRegularExpression alloc]initWithPattern:@"^[1-9][0-9]{5}19[0-9]{2}((01|03|05|07|08|10|12)(0[1-9]|[1-2][0-9]|3[0-1])|(04|06|09|11)(0[1-9]|[1-2][0-9]|30)|02(0[1-9]|[1-2][0-9]))[0-9]{3}[0-9Xx]$"
                                                                        options:NSRegularExpressionCaseInsensitive
                                                                          error:nil];//测试出生日期的合法性
            }
            else {
                regularExpression = [[NSRegularExpression alloc]initWithPattern:@"^[1-9][0-9]{5}19[0-9]{2}((01|03|05|07|08|10|12)(0[1-9]|[1-2][0-9]|3[0-1])|(04|06|09|11)(0[1-9]|[1-2][0-9]|30)|02(0[1-9]|1[0-9]|2[0-8]))[0-9]{3}[0-9Xx]$"
                                                                        options:NSRegularExpressionCaseInsensitive
                                                                          error:nil];//测试出生日期的合法性
            }
            numberofMatch = [regularExpression numberOfMatchesInString:cardId
                                                               options:NSMatchingReportProgress
                                                                 range:NSMakeRange(0, cardId.length)];
            
            
            if(numberofMatch >0) {
                int S = ([cardId substringWithRange:NSMakeRange(0,1)].intValue + [cardId substringWithRange:NSMakeRange(10,1)].intValue) *7 +
                ([cardId substringWithRange:NSMakeRange(1,1)].intValue + [cardId substringWithRange:NSMakeRange(11,1)].intValue) *9 +
                ([cardId substringWithRange:NSMakeRange(2,1)].intValue + [cardId substringWithRange:NSMakeRange(12,1)].intValue) *10 +
                ([cardId substringWithRange:NSMakeRange(3,1)].intValue + [cardId substringWithRange:NSMakeRange(13,1)].intValue) *5 +
                ([cardId substringWithRange:NSMakeRange(4,1)].intValue + [cardId substringWithRange:NSMakeRange(14,1)].intValue) *8 +
                ([cardId substringWithRange:NSMakeRange(5,1)].intValue + [cardId substringWithRange:NSMakeRange(15,1)].intValue) *4 +
                ([cardId substringWithRange:NSMakeRange(6,1)].intValue + [cardId substringWithRange:NSMakeRange(16,1)].intValue) *2 +
                [cardId substringWithRange:NSMakeRange(7,1)].intValue *1 + [cardId substringWithRange:NSMakeRange(8,1)].intValue *6 +
                [cardId substringWithRange:NSMakeRange(9,1)].intValue *3;
                int Y = S %11;
                NSString *M =@"F";
                NSString *JYM =@"10X98765432";
                M = [JYM substringWithRange:NSMakeRange(Y,1)];// 判断校验位
                if ([M isEqualToString:[cardId substringWithRange:NSMakeRange(17,1)]]) {
                    return YES;// 检测ID的校验位
                }
                else {
                    return NO;
                }
            }
            else {
                return NO;
            }
        default:
            return NO;
    }
    return NO;
}

下面我们就看一下调用过程

    NSString *str1 = @"990606198808183611";
    BOOL result1 = [str1 jj_isCardIdValid];
    NSLog(@"result1 = %d", result1);

下面看输出结果

2017-12-16 00:39:31.180822+0800 JJNSStringTool[2099:49567] result1 = 0

正确的身份证号码我就不去验证了,大家可以自行去验证。


判断是否是整数

还是直接看代码

// 判断是否是整数

- (BOOL)jj_isIntNumber;
// 判断是否是整数

- (BOOL)jj_isIntNumber
{
    NSString *regex = @"^-?[0-9]\\d*$";
    NSPredicate *predicate = [NSPredicate predicateWithFormat:@"SELF MATCHES %@",regex];
    return [predicate evaluateWithObject:self];
}

这里就不给大家验证了,大家感兴趣的可以自行验证。


判断是否是小数

还是直接看代码

//判断是否是小数

- (BOOL)jj_isFloatNumber;
//判断是否是小数

- (BOOL)jj_isFloatNumber
{
    NSString *regex = @"^-?([1-9]\\d*\\.\\d*|0\\.\\d*[1-9]\\d*|0?\\.0+|0)$";
    NSPredicate *predicate = [NSPredicate predicateWithFormat:@"SELF MATCHES %@",regex];
    return [predicate evaluateWithObject:self];
}

这里就带着大家一起验证下。

//是否是小数

- (void)isFloatNumber
{
    NSString *str = @"12.13";
    BOOL result = [str jj_isFloatNumber];
    NSLog(@"result = %d", result);
    
    NSString *str1 = @"999";
    BOOL result1 = [str1 jj_isFloatNumber];
    NSLog(@"result1 = %d", result1);
}

看输出结果

2017-12-16 00:51:41.022796+0800 JJNSStringTool[2221:55765] result = 1
2017-12-16 00:51:41.023191+0800 JJNSStringTool[2221:55765] result1 = 0

可以,看见可以很好的识别是否是小数。

后记

未完,待续~~~

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 158,847评论 4 362
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 67,208评论 1 292
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 108,587评论 0 243
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 43,942评论 0 205
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 52,332评论 3 287
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 40,587评论 1 218
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 31,853评论 2 312
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 30,568评论 0 198
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 34,273评论 1 242
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 30,542评论 2 246
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 32,033评论 1 260
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 28,373评论 2 253
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 33,031评论 3 236
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 26,073评论 0 8
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 26,830评论 0 195
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 35,628评论 2 274
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 35,537评论 2 269

推荐阅读更多精彩内容