NSString+RegexCategory.m 15 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367
  1. //
  2. // NSString+RegexCategory.h
  3. // IOS-Categories
  4. //
  5. // Created by KevinHM on 15/6/24.
  6. // Copyright (c) 2015年 KevinHM. All rights reserved.
  7. // https://github.com/KevinHM
  8. //
  9. #import "NSString+RegexCategory.h"
  10. @implementation NSString (RegexCategory)
  11. #pragma mark - 正则相关
  12. - (BOOL)isValidateByRegex:(NSString *)regex{
  13. NSPredicate *pre = [NSPredicate predicateWithFormat:@"SELF MATCHES %@",regex];
  14. return [pre evaluateWithObject:self];
  15. }
  16. #pragma mark -
  17. //手机号分服务商
  18. - (BOOL)isMobileNumberClassification{
  19. /**
  20. * 手机号码
  21. * 移动:134[0-8],135,136,137,138,139,150,151,157,158,159,182,187,188,1705
  22. * 联通:130,131,132,152,155,156,185,186,1709
  23. * 电信:133,1349,153,180,189,1700
  24. */
  25. // NSString * MOBILE = @"^1((3//d|5[0-35-9]|8[025-9])//d|70[059])\\d{7}$";//总况
  26. /**
  27. 10 * 中国移动:China Mobile
  28. 11 * 134[0-8],135,136,137,138,139,150,151,157,158,159,182,187,188,1705
  29. 12 */
  30. NSString * CM = @"^1(34[0-8]|(3[5-9]|5[017-9]|8[278])\\d|705)\\d{7}$";
  31. /**
  32. 15 * 中国联通:China Unicom
  33. 16 * 130,131,132,152,155,156,185,186,1709
  34. 17 */
  35. NSString * CU = @"^1((3[0-2]|5[256]|8[56])\\d|709)\\d{7}$";
  36. /**
  37. 20 * 中国电信:China Telecom
  38. 21 * 133,1349,153,180,189,1700
  39. 22 */
  40. NSString * CT = @"^1((33|53|8[09])\\d|349|700)\\d{7}$";
  41. /**
  42. 25 * 大陆地区固话及小灵通
  43. 26 * 区号:010,020,021,022,023,024,025,027,028,029
  44. 27 * 号码:七位或八位
  45. 28 */
  46. NSString * PHS = @"^0(10|2[0-5789]|\\d{3})\\d{7,8}$";
  47. // NSPredicate *regextestmobile = [NSPredicate predicateWithFormat:@"SELF MATCHES %@", MOBILE];
  48. if (([self isValidateByRegex:CM])
  49. || ([self isValidateByRegex:CU])
  50. || ([self isValidateByRegex:CT])
  51. || ([self isValidateByRegex:PHS]))
  52. {
  53. return YES;
  54. }
  55. else
  56. {
  57. return NO;
  58. }
  59. }
  60. //手机号有效性
  61. - (BOOL)isMobileNumber{
  62. /**
  63. * 手机号以13、15、18、170开头,8个 \d 数字字符
  64. * 小灵通 区号:010,020,021,022,023,024,025,027,028,029 还有未设置的新区号xxx
  65. */
  66. NSString *mobileNoRegex = @"^1((3\\d|5[0-35-9]|8[025-9])\\d|70[059])\\d{7}$";//除4以外的所有个位整数,不能使用[^4,\\d]匹配,这里是否iOS Bug?
  67. NSString *phsRegex =@"^0(10|2[0-57-9]|\\d{3})\\d{7,8}$";
  68. BOOL ret = [self isValidateByRegex:mobileNoRegex];
  69. BOOL ret1 = [self isValidateByRegex:phsRegex];
  70. return (ret || ret1);
  71. }
  72. //邮箱
  73. - (BOOL)isEmailAddress{
  74. NSString *emailRegex = @"[A-Za-z0-9._%+-]+@[A-Za-z0-9.-]+\\.[A-Za-z]{2,4}";
  75. return [self isValidateByRegex:emailRegex];
  76. }
  77. //身份证号
  78. - (BOOL) simpleVerifyIdentityCardNum
  79. {
  80. NSString *regex2 = @"^(\\d{14}|\\d{17})(\\d|[xX])$";
  81. return [self isValidateByRegex:regex2];
  82. }
  83. //车牌
  84. - (BOOL)isCarNumber{
  85. //车牌号:湘K-DE829 香港车牌号码:粤Z-J499港
  86. NSString *carRegex = @"^[\u4e00-\u9fff]{1}[a-zA-Z]{1}[-][a-zA-Z_0-9]{4}[a-zA-Z_0-9_\u4e00-\u9fff]$";//其中\u4e00-\u9fa5表示unicode编码中汉字已编码部分,\u9fa5-\u9fff是保留部分,将来可能会添加
  87. return [self isValidateByRegex:carRegex];
  88. }
  89. - (BOOL)isMacAddress{
  90. NSString * macAddRegex = @"([A-Fa-f\\d]{2}:){5}[A-Fa-f\\d]{2}";
  91. return [self isValidateByRegex:macAddRegex];
  92. }
  93. - (BOOL)isValidUrl
  94. {
  95. NSString *regex = @"^((http)|(https))+:[^\\s]+\\.[^\\s]*$";
  96. return [self isValidateByRegex:regex];
  97. }
  98. - (BOOL)isValidChinese;
  99. {
  100. NSString *chineseRegex = @"^[\u4e00-\u9fa5]+$";
  101. return [self isValidateByRegex:chineseRegex];
  102. }
  103. - (BOOL)isValidPostalcode {
  104. NSString *postalRegex = @"^[0-8]\\d{5}(?!\\d)$";
  105. return [self isValidateByRegex:postalRegex];
  106. }
  107. - (BOOL)isValidTaxNo
  108. {
  109. NSString *taxNoRegex = @"[0-9]\\d{13}([0-9]|X)$";
  110. return [self isValidateByRegex:taxNoRegex];
  111. }
  112. - (BOOL)isValidPasswordFomatter{
  113. NSString *taxNoRegex = @"^[a-zA-Z0-9_]{6,12}+$";
  114. return [self isValidateByRegex:taxNoRegex];
  115. }
  116. - (BOOL)isValidNickName{
  117. NSString *taxNoRegex = @"^[a-zA-Z0-9\u4e00-\u9fa5_-]{4,20}+$";
  118. return [self isValidateByRegex:taxNoRegex];
  119. }
  120. - (BOOL)isValidWithMinLenth:(NSInteger)minLenth
  121. maxLenth:(NSInteger)maxLenth
  122. containChinese:(BOOL)containChinese
  123. firstCannotBeDigtal:(BOOL)firstCannotBeDigtal;
  124. {
  125. // [\u4e00-\u9fa5A-Za-z0-9_]{4,20}
  126. NSString *hanzi = containChinese ? @"\u4e00-\u9fa5" : @"";
  127. NSString *first = firstCannotBeDigtal ? @"^[a-zA-Z_]" : @"";
  128. NSString *regex = [NSString stringWithFormat:@"%@[%@A-Za-z0-9_]{%d,%d}", first, hanzi, (int)(minLenth-1), (int)(maxLenth-1)];
  129. return [self isValidateByRegex:regex];
  130. }
  131. - (BOOL)isValidWithMinLenth:(NSInteger)minLenth
  132. maxLenth:(NSInteger)maxLenth
  133. containChinese:(BOOL)containChinese
  134. containDigtal:(BOOL)containDigtal
  135. containLetter:(BOOL)containLetter
  136. containOtherCharacter:(NSString *)containOtherCharacter
  137. firstCannotBeDigtal:(BOOL)firstCannotBeDigtal;
  138. {
  139. NSString *hanzi = containChinese ? @"\u4e00-\u9fa5" : @"";
  140. NSString *first = firstCannotBeDigtal ? @"^[a-zA-Z_]" : @"";
  141. NSString *lengthRegex = [NSString stringWithFormat:@"(?=^.{%@,%@}$)", @(minLenth), @(maxLenth)];
  142. NSString *digtalRegex = containDigtal ? @"(?=(.*\\d.*){1})" : @"";
  143. NSString *letterRegex = containLetter ? @"(?=(.*[a-zA-Z].*){1})" : @"";
  144. NSString *characterRegex = [NSString stringWithFormat:@"(?:%@[%@A-Za-z0-9%@]+)", first, hanzi, containOtherCharacter ? containOtherCharacter : @""];
  145. NSString *regex = [NSString stringWithFormat:@"%@%@%@%@", lengthRegex, digtalRegex, letterRegex, characterRegex];
  146. return [self isValidateByRegex:regex];
  147. }
  148. #pragma mark - 算法相关
  149. //精确的身份证号码有效性检测
  150. + (BOOL)accurateVerifyIDCardNumber:(NSString *)value {
  151. value = [value stringByTrimmingCharactersInSet:[NSCharacterSet whitespaceAndNewlineCharacterSet]];
  152. int length =0;
  153. if (!value) {
  154. return NO;
  155. }else {
  156. length = (int)value.length;
  157. if (length !=15 && length !=18) {
  158. return NO;
  159. }
  160. }
  161. // 省份代码
  162. 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"];
  163. NSString *valueStart2 = [value substringToIndex:2];
  164. BOOL areaFlag =NO;
  165. for (NSString *areaCode in areasArray) {
  166. if ([areaCode isEqualToString:valueStart2]) {
  167. areaFlag =YES;
  168. break;
  169. }
  170. }
  171. if (!areaFlag) {
  172. return false;
  173. }
  174. NSRegularExpression *regularExpression;
  175. NSUInteger numberofMatch;
  176. int year =0;
  177. switch (length) {
  178. case 15:
  179. year = [value substringWithRange:NSMakeRange(6,2)].intValue +1900;
  180. if (year %4 ==0 || (year %100 ==0 && year %4 ==0)) {
  181. 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}$"
  182. options:NSRegularExpressionCaseInsensitive
  183. error:nil];//测试出生日期的合法性
  184. }else {
  185. 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}$"
  186. options:NSRegularExpressionCaseInsensitive
  187. error:nil];//测试出生日期的合法性
  188. }
  189. numberofMatch = [regularExpression numberOfMatchesInString:value
  190. options:NSMatchingReportProgress
  191. range:NSMakeRange(0, value.length)];
  192. if(numberofMatch >0) {
  193. return YES;
  194. }else {
  195. return NO;
  196. }
  197. case 18:
  198. year = [value substringWithRange:NSMakeRange(6,4)].intValue;
  199. if (year %4 ==0 || (year %100 ==0 && year %4 ==0)) {
  200. 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]$"
  201. options:NSRegularExpressionCaseInsensitive
  202. error:nil];//测试出生日期的合法性
  203. }else {
  204. 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]$"
  205. options:NSRegularExpressionCaseInsensitive
  206. error:nil];//测试出生日期的合法性
  207. }
  208. numberofMatch = [regularExpression numberOfMatchesInString:value
  209. options:NSMatchingReportProgress
  210. range:NSMakeRange(0, value.length)];
  211. if(numberofMatch >0) {
  212. int S = ([value substringWithRange:NSMakeRange(0,1)].intValue + [value substringWithRange:NSMakeRange(10,1)].intValue) *7 + ([value substringWithRange:NSMakeRange(1,1)].intValue + [value substringWithRange:NSMakeRange(11,1)].intValue) *9 + ([value substringWithRange:NSMakeRange(2,1)].intValue + [value substringWithRange:NSMakeRange(12,1)].intValue) *10 + ([value substringWithRange:NSMakeRange(3,1)].intValue + [value substringWithRange:NSMakeRange(13,1)].intValue) *5 + ([value substringWithRange:NSMakeRange(4,1)].intValue + [value substringWithRange:NSMakeRange(14,1)].intValue) *8 + ([value substringWithRange:NSMakeRange(5,1)].intValue + [value substringWithRange:NSMakeRange(15,1)].intValue) *4 + ([value substringWithRange:NSMakeRange(6,1)].intValue + [value substringWithRange:NSMakeRange(16,1)].intValue) *2 + [value substringWithRange:NSMakeRange(7,1)].intValue *1 + [value substringWithRange:NSMakeRange(8,1)].intValue *6 + [value substringWithRange:NSMakeRange(9,1)].intValue *3;
  213. int Y = S %11;
  214. NSString *M =@"F";
  215. NSString *JYM =@"10X98765432";
  216. M = [JYM substringWithRange:NSMakeRange(Y,1)];// 判断校验位
  217. if ([M isEqualToString:[value substringWithRange:NSMakeRange(17,1)]]) {
  218. return YES;// 检测ID的校验位
  219. }else {
  220. return NO;
  221. }
  222. }else {
  223. return NO;
  224. }
  225. default:
  226. return NO;
  227. }
  228. }
  229. /** 银行卡号有效性问题Luhn算法
  230. * 现行 16 位银联卡现行卡号开头 6 位是 622126~622925 之间的,7 到 15 位是银行自定义的,
  231. * 可能是发卡分行,发卡网点,发卡序号,第 16 位是校验码。
  232. * 16 位卡号校验位采用 Luhm 校验方法计算:
  233. * 1,将未带校验位的 15 位卡号从右依次编号 1 到 15,位于奇数位号上的数字乘以 2
  234. * 2,将奇位乘积的个十位全部相加,再加上所有偶数位上的数字
  235. * 3,将加法和加上校验位能被 10 整除。
  236. */
  237. - (BOOL)bankCardluhmCheck{
  238. NSString * lastNum = [[self substringFromIndex:(self.length-1)] copy];//取出最后一位
  239. NSString * forwardNum = [[self substringToIndex:(self.length -1)] copy];//前15或18位
  240. NSMutableArray * forwardArr = [[NSMutableArray alloc] initWithCapacity:0];
  241. for (int i=0; i<forwardNum.length; i++) {
  242. NSString * subStr = [forwardNum substringWithRange:NSMakeRange(i, 1)];
  243. [forwardArr addObject:subStr];
  244. }
  245. NSMutableArray * forwardDescArr = [[NSMutableArray alloc] initWithCapacity:0];
  246. for (int i = (int)(forwardArr.count-1); i> -1; i--) {//前15位或者前18位倒序存进数组
  247. [forwardDescArr addObject:forwardArr[i]];
  248. }
  249. NSMutableArray * arrOddNum = [[NSMutableArray alloc] initWithCapacity:0];//奇数位*2的积 < 9
  250. NSMutableArray * arrOddNum2 = [[NSMutableArray alloc] initWithCapacity:0];//奇数位*2的积 > 9
  251. NSMutableArray * arrEvenNum = [[NSMutableArray alloc] initWithCapacity:0];//偶数位数组
  252. for (int i=0; i< forwardDescArr.count; i++) {
  253. NSInteger num = [forwardDescArr[i] intValue];
  254. if (i%2) {//偶数位
  255. [arrEvenNum addObject:[NSNumber numberWithInteger:num]];
  256. }else{//奇数位
  257. if (num * 2 < 9) {
  258. [arrOddNum addObject:[NSNumber numberWithInteger:num * 2]];
  259. }else{
  260. NSInteger decadeNum = (num * 2) / 10;
  261. NSInteger unitNum = (num * 2) % 10;
  262. [arrOddNum2 addObject:[NSNumber numberWithInteger:unitNum]];
  263. [arrOddNum2 addObject:[NSNumber numberWithInteger:decadeNum]];
  264. }
  265. }
  266. }
  267. __block NSInteger sumOddNumTotal = 0;
  268. [arrOddNum enumerateObjectsUsingBlock:^(NSNumber * obj, NSUInteger idx, BOOL *stop) {
  269. sumOddNumTotal += [obj integerValue];
  270. }];
  271. __block NSInteger sumOddNum2Total = 0;
  272. [arrOddNum2 enumerateObjectsUsingBlock:^(NSNumber * obj, NSUInteger idx, BOOL *stop) {
  273. sumOddNum2Total += [obj integerValue];
  274. }];
  275. __block NSInteger sumEvenNumTotal =0 ;
  276. [arrEvenNum enumerateObjectsUsingBlock:^(NSNumber * obj, NSUInteger idx, BOOL *stop) {
  277. sumEvenNumTotal += [obj integerValue];
  278. }];
  279. NSInteger lastNumber = [lastNum integerValue];
  280. NSInteger luhmTotal = lastNumber + sumEvenNumTotal + sumOddNum2Total + sumOddNumTotal;
  281. return (luhmTotal%10 ==0)?YES:NO;
  282. }
  283. - (BOOL)isIPAddress{
  284. NSString *regex = [NSString stringWithFormat:@"^(\\d{1,3})\\.(\\d{1,3})\\.(\\d{1,3})\\.(\\d{1,3})$"];
  285. NSPredicate *pre = [NSPredicate predicateWithFormat:@"SELF MATCHES %@",regex];
  286. BOOL rc = [pre evaluateWithObject:self];
  287. if (rc) {
  288. NSArray *componds = [self componentsSeparatedByString:@","];
  289. BOOL v = YES;
  290. for (NSString *s in componds) {
  291. if (s.integerValue > 255) {
  292. v = NO;
  293. break;
  294. }
  295. }
  296. return v;
  297. }
  298. return NO;
  299. }
  300. @end