Regex 正则表达式

1、Regex

  • 定义

    • 正则表达式又称正规表示法、常规表示法(英语:Regular Expression,在代码中常简写为 regex、regexp 或 RE),计算机科学的一个概念。正则表达式使用单个字符串来描述、匹配一系列符合某个句法规则的字符串。在很多文本编辑器里,正则表达式通常被用来检索、替换那些符合某个模式的文本;
  • 使用步骤

    • 1、定义正则表达式规则
    • 2、通过规则,创建正则表达式对象
    • 3、利用正则表达式对象匹配字符串

    • 注意:正则表达式通常缩写成 “regex”

2、语法介绍

  • 正则表达式语法介绍

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    37
    38
    39
    40
    41
    42
    43
    44
    45
    46
    47
    48
    49
    50
    51
    52
    53
    54
    55
    56
    57
    58
    59
    @"^[0-9]+$"

    它代表了字符串中只能包含 >=10-9 的数字。
    语法是不是有一些怪异?下面我们先撇开 iOS 中的正则表达式的语法,用通俗的正则表达式语法来为介绍一下。
    iOS 语法与通俗的正则表达式语法相同,不同在于对转义字符的处理上(语言类的都相同)。

    语法:
    特殊符号 '^''$'。他们的作用是分别指出一个字符串的开始和结束:
    “^one”:表示所有以 ”one” 开始的字符串(”one cat”,”one123″,·····);
    类似于:- (BOOL)hasPrefix:(NSString )aString;
    “a dog$”:表示所以以 ”a dog” 结尾的字符串(”it is a dog”,·····);
    类似于:- (BOOL)hasSuffix:(NSString )aString;
    “^apple$”:表示开始和结尾都是 ”apple” 的字符串,这个是唯一的;
    “banana”:表示任何包含 ”banana” 的字符串。
    类似于 iOS8 的新方法 - (BOOL)containsString:(NSString )aString,搜索子串用的。

    ‘','+' 和 '?' 这三个符号,表示一个或 N 个字符重复出现的次数:
    它们分别表示 “没有或更多”([0, +∞] 取整),“一次或更多”([1, +∞] 取整),“没有或一次”([0, 1] 取整)。
    “ab”:表示一个字符串有一个 a 后面跟着零个或若干个 b(”a”, “ab”, “abbb”, ……);
    “ab+”:表示一个字符串有一个 a 后面跟着至少一个 b 或者更多( ”ab”, “abbb”, ……);
    “ab?”:表示一个字符串有一个 a 后面跟着零个或者一个 b( ”a”, “ab”);
    “a?b+$”:表示在字符串的末尾有零个或一个 a 跟着一个或几个 b( ”b”, “ab”, ”bb”, ”abb”, ……)。
      
       用大括号括起来 “{}”,表示一个重复的具体范围:
       “ab{4}”:表示一个字符串有一个 a 跟着 4 个 b(”abbbb”);
       “ab{1,}”:表示一个字符串有一个 a 跟着至少 1 个 b(”ab”, ”abb”, ”abbb”, ……);
       “ab{3,4}”:表示一个字符串有一个 a 跟着 34 个 b(”abbb”, ”abbbb”)。
       那么,“” 可以用 {0,} 表示,“+” 可以用 {1,} 表示,“?” 可以用 {01} 表示
       注意:可以没有下限,但是不能没有上限!例如 “ab{,5}” 是错误的写法
      
       “|” 表示 “或” 操作:
       “a|b”:表示一个字符串里有 ”a” 或者 ”b”;
       “(a|bcd)ef”:表示 ”aef” 或 ”bcdef”;
       “(a|b)*c”:表示一串 ”a” "b” 混合的字符串后面跟一个 ”c”;
      
       方括号 “[]” 表示在括号内的众多字符中,选择 1-N 个括号内的符合语法的字符作为结果:
       “[ab]“:表示一个字符串有一个 ”a” 或 ”b”(相当于 ”a|b”);
       “[a-d]“:表示一个字符串包含小写的 'a' 到 'd' 中的一个(相当于 ”a|b|c|d” 或者 ”[abcd]“);
       “^[a-zA-Z]“:表示一个以字母开头的字符串;
       “[0-9]a”:表示 a 前有一位的数字;
       “[a-zA-Z0-9]$”:表示一个字符串以一个字母或数字结束。
      
       “.” 匹配除 “\r\n” 之外的任何单个字符:
       “a.[a-z]“:表示一个字符串有一个 ”a” 后面跟着一个任意字符和一个小写字母;
       “^.{5}$”:表示任意 1 个长度为 5 的字符串;
      
    “\num” 其中 num 是一个正整数。表示 ”\num” 之前的字符出现相同的个数:
       “(.)\1″:表示两个连续的相同字符。
      
       在方括号里用 '^' 表示不希望出现的字符,'^' 应在方括号里的第一位:
       “@[^a-zA-Z]4@”:表示两个 ”@” 中不应该出现字母。
      
       常用的还有:
       iOS 中书写正则表达式,碰到转义字符,多加一个 “\”,例如:全数字字符:@”^\d+$”
      
       “\d” 匹配一个数字字符。等价于 “[0-9]”。
       “\D” 匹配一个非数字字符。等价于 “[^0-9]”。
       “\w” 匹配包括下划线的任何单词字符。等价于 “[A-Za-z0-9_]”。
       “\W” 匹配任何非单词字符。等价于 “[^A-Za-z0-9_]”。

3、常用的正则表达式

  • 常用的正则表达式

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    37
    38
    39
    40
    41
    42
    43
    44
    45
    1.验证用户名和密码:”^[a-zA-Z]\w{5,15}$”
    2.验证电话号码:(”^([\\d{3,4}-)\\d{7,8}$](file:///d%7B3,4%7D-)//d%7B7,8%7D$)”)
    eg:021-68686868 0511-6868686
    3.验证手机号码:”^1[3|4|5|7|8][0-9]\\d{8}$”;
    4.验证身份证号(15位或18位数字):”\\d{14}[[0-9],0-9xX]”;
    5.验证 Email 地址:(“^\\w+([-+.]\\w+)*@\\w+([-.]\\w+)*\.\\w+([-.]\\w+)*$”);
    6.只能输入由数字和 26 个英文字母组成的字符串:(“^[A-Za-z0-9]+$”) ;
    7.整数或者小数:^[0-9]+([.]{0,1}[0-9]+){0,1}$
    8.只能输入数字:”^[0-9]*$”。
    9.只能输入 n 位的数字:”^\\d{n}$”。
    10.只能输入至少 n 位的数字:”^\\d{n,}$”。
    11.只能输入 m~n 位的数字:”^\\d{m,n}$”。
    12.只能输入零和非零开头的数字:”^(0|[1-9][0-9]*)$”。
    13.只能输入有两位小数的正实数:”^[0-9]+(.[0-9]{2})?$”。
    14.只能输入有 1~3 位小数的正实数:”^[0-9]+(\.[0-9]{1,3})?$”。
    15.只能输入非零的正整数:”^\+?[1-9][0-9]*$”。
    16.只能输入非零的负整数:”^\-[1-9][]0-9″*$。
    17.只能输入长度为 3 的字符:”^.{3}$”。
    18.只能输入由 26 个英文字母组成的字符串:”^[A-Za-z]+$”。
    19.只能输入由 26 个大写英文字母组成的字符串:”^[A-Z]+$”。
    20.只能输入由 26 个小写英文字母组成的字符串:”^[a-z]+$”。
    21.验证是否含有 ^%&',;=?$\” 等字符:”[^%&',;=?$\x22]+”。
    22.只能输入汉字:”^[\u4e00-\u9fa5]{0,}$”。
    23.验证 URL:"http(s)?://([\\w-]+\\.)+[\\w-]+(/[\\w- ./?%&=]*)?"
    24.验证一年的 12 个月:”^(0?[1-9]|1[0-2])$”正确格式为:”01″~”09″和”10″~”12″。
    25.验证一个月的 31 天:”^((0?[1-9])|((1|2)[0-9])|30|31)$”正确格式为;”01″~”09″、”10″~”29″和“30”~“31”。
    26.获取日期正则表达式:[\\d{4](file:///d%7B4)}[年|\-|\.]\\d{\1-\12}[月|\-|\.]\\d{\1-\31}日?
    评注:可用来匹配大多数年月日信息。
    27.匹配双字节字符(包括汉字在内):[^\x00-\xff]
    评注:可以用来计算字符串的长度(一个双字节字符长度计2,ASCII字符计1
    28.匹配空白行的正则表达式:\n\s*\r
    评注:可以用来删除空白行
    29.匹配HTML标记的正则表达式:<(\S*?)[^>]*>.*?</>|<.*? />
    评注:网上流传的版本太糟糕,上面这个也仅仅能匹配部分,对于复杂的嵌套标记依旧无能为力
    30.匹配首尾空白字符的正则表达式:^\s*|\s*$
    评注:可以用来删除行首行尾的空白字符(包括空格、制表符、换页符等等),非常有用的表达式
    31.匹配网址URL的正则表达式:[a-zA-z]+://[^\s]*
    评注:网上流传的版本功能很有限,上面这个基本可以满足需求
    32.匹配帐号是否合法(字母开头,允许5-16字节,允许字母数字下划线):^[a-zA-Z][a-zA-Z0-9_]{4,15}$
    评注:表单验证时很实用
    33.匹配腾讯 QQ 号:[1-9][0-9]\{4,\}
    评注:腾讯 QQ 号从10 000 开始
    34.匹配中国邮政编码:[1-9]\\d{5}(?!\d)
    评注:中国邮政编码为 6 位数字
    35.匹配 ip 地址:((2[0-4]\\d|25[0-5]|[01]?\\d\\d?)\.){3}(2[0-4]\\d|25[0-5]|[01]?\\d\\d?)。

4、正则表达式的使用

4.1 正则表达式使用

  • 具体实现代码见 GitHub 源码 QExtension

    • NSString+Regex.h

      1
      2
      3
      4
      5
      6
      7
      8
      9
      10
      11
      12
      13
      14
      15
      16
      17
      18
      19
      20
      21
      22
      23
      24
      25
      26
      27
      28
      29
      30
      31
      32
      33
      34
      35
      36
      37
      38
      39
      40
      41
      42
      43
      44
      45
      46
      47
      48
      49
      50
      51
      52
      53
      54
      55
      56
      57
      58
      59
      60
      61
      62
      63
      64
      65
      66
      67
      68
      69
      70
      71
      72
      73
      74
      75
      76
      77
      78
      79
      80
      81
      82
      83
      84
      85
      86
      87
      88
      89
      90
      91
      92
      93
      94
      95
      96
      97
      98
      99
      100
      101
      102
      103
      104
      105
      106
      107
      108
      109
      110
      111
      112
      113
      114
      115
      116
      117
      @interface NSString (Regex)

      /**
      * 手机号有效性判断
      *
      * @return 有效性结果,YES 有效,NO 无效
      */
      - (BOOL)q_isValidMobileNum;

      /**
      * 手机号分服务商有效性判断
      *
      * @return 有效性结果,YES 有效,NO 无效
      */
      - (BOOL)q_isValidMobileNumClassification;

      /**
      * 邮箱有效性判断
      *
      * @return 有效性结果,YES 有效,NO 无效
      */
      - (BOOL)q_isValidEmailAddress;

      /**
      * 邮编有效性判断
      *
      * @return 有效性结果,YES 有效,NO 无效
      */
      - (BOOL)q_isValidPostalcode;

      /**
      * 车牌号有效性判断
      *
      * @return 有效性结果,YES 有效,NO 无效
      */
      - (BOOL)q_isValidCarNum;

      /**
      * 中文有效性判断
      *
      * @return 有效性结果,YES 有效,NO 无效
      */
      - (BOOL)q_isValidChinese;

      /**
      * Mac 地址有效性判断
      *
      * @return 有效性结果,YES 有效,NO 无效
      */
      - (BOOL)q_isValidMacAddress;

      /**
      * Url 地址有效性判断
      *
      * @return 有效性结果,YES 有效,NO 无效
      */
      - (BOOL)q_isValidUrlAddress;

      /**
      * IP 地址有效性判断
      *
      * @return 有效性结果,YES 有效,NO 无效
      */
      - (BOOL)q_isValidIPAddress;

      /**
      * 简单的身份证号码有效性检测
      *
      * @return 有效性结果,YES 有效,NO 无效
      */
      - (BOOL)q_isSimpleVerifyIdentityCardNum;

      /**
      * 精确的身份证号码有效性检测
      *
      * @return 有效性结果,YES 有效,NO 无效
      */
      - (BOOL)q_isAccurateVerifyIdentityCardNum;

      /**
      * 银行卡号有效性判断
      *
      * @return 有效性结果,YES 有效,NO 无效
      */
      - (BOOL)q_isValidBankCardNum;

      /**
      * 税号有效性判断
      *
      * @return 有效性结果,YES 有效,NO 无效
      */
      - (BOOL)q_isValidTaxNum;

      /**
      * 有效性判断
      *
      * @return 有效性结果,YES 有效,NO 无效
      */
      - (BOOL)q_isValidWithMinLenth:(NSInteger)minLenth
      maxLenth:(NSInteger)maxLenth
      containChinese:(BOOL)containChinese
      firstCannotBeDigtal:(BOOL)firstCannotBeDigtal;

      /**
      * 有效性判断
      *
      * @return 有效性结果,YES 有效,NO 无效
      */
      - (BOOL)q_isValidWithMinLenth:(NSInteger)minLenth
      maxLenth:(NSInteger)maxLenth
      containChinese:(BOOL)containChinese
      containDigtal:(BOOL)containDigtal
      containLetter:(BOOL)containLetter
      containOtherCharacter:(NSString *)containOtherCharacter
      firstCannotBeDigtal:(BOOL)firstCannotBeDigtal;

      @end
    • NSString+Regex.m

      1
      2
      3
      4
      5
      6
      7
      8
      9
      10
      11
      12
      13
      14
      15
      16
      17
      18
      19
      20
      21
      22
      23
      24
      25
      26
      27
      28
      29
      30
      31
      32
      33
      34
      35
      36
      37
      38
      39
      40
      41
      42
      43
      44
      45
      46
      47
      48
      49
      50
      51
      52
      53
      54
      55
      56
      57
      58
      59
      60
      61
      62
      63
      64
      65
      66
      67
      68
      69
      70
      71
      72
      73
      74
      75
      76
      77
      78
      79
      80
      81
      82
      83
      84
      85
      86
      87
      88
      89
      90
      91
      92
      93
      94
      95
      96
      97
      98
      99
      100
      101
      102
      103
      104
      105
      106
      107
      108
      109
      110
      111
      112
      113
      114
      115
      116
      117
      118
      119
      120
      121
      122
      123
      124
      125
      126
      127
      128
      129
      130
      131
      132
      133
      134
      135
      136
      137
      138
      139
      140
      141
      142
      143
      144
      145
      146
      147
      148
      149
      150
      151
      152
      153
      154
      155
      156
      157
      158
      159
      160
      161
      162
      163
      164
      165
      166
      167
      168
      169
      170
      171
      172
      173
      174
      175
      176
      177
      178
      179
      180
      181
      182
      183
      184
      185
      186
      187
      188
      189
      190
      191
      192
      193
      194
      195
      196
      197
      198
      199
      200
      201
      202
      203
      204
      205
      206
      207
      208
      209
      210
      211
      212
      213
      214
      215
      216
      217
      218
      219
      220
      221
      222
      223
      224
      225
      226
      227
      228
      229
      230
      231
      232
      233
      234
      235
      236
      237
      238
      239
      240
      241
      242
      243
      244
      245
      246
      247
      248
      249
      250
      251
      252
      253
      254
      255
      256
      257
      258
      259
      260
      261
      262
      263
      264
      265
      266
      267
      268
      269
      270
      271
      272
      273
      274
      275
      276
      277
      278
      279
      280
      281
      282
      283
      284
      285
      286
      287
      288
      289
      290
      291
      292
      293
      294
      295
      296
      297
      298
      299
      300
      301
      302
      303
      304
      305
      306
      307
      308
      309
      310
      311
      312
      313
      314
      315
      316
      317
      318
      319
      320
      321
      322
      323
      324
      325
      326
      327
      328
      329
      330
      331
      332
      333
      334
      335
      336
      337
      338
      339
      340
      341
      342
      343
      344
      345
      346
      347
      348
      349
      350
      351
      352
      353
      354
      355
      356
      357
      358
      359
      360
      361
      362
      363
      364
      365
      366
      367
      368
      369
      370
      371
      372
      373
      374
      375
      376
      377
      378
      379
      380
      381
      382
      383
      384
      385
      386
      387
      388
      389
      390
      391
      @implementation NSString (Regex)

      #pragma mark - 正则表达式有效性判断

      /// 手机号有效性
      - (BOOL)q_isValidMobileNum {

      /**
      * 手机号以 13、15、18、170 开头,8 个 \d 数字字符
      * 小灵通 区号:010, 020, 021, 022, 023, 024, 025, 027, 028, 029 还有未设置的新区号xxx
      */
      NSString *mobileNoRegex = @"^1((3\\d|5[0-35-9]|8[025-9])\\d|70[059])\\d{7}$";
      NSString *phsRegex =@"^0(10|2[0-57-9]|\\d{3})\\d{7,8}$";

      BOOL ret = [self q_isValidateByRegex:mobileNoRegex];
      BOOL ret1 = [self q_isValidateByRegex:phsRegex];

      return (ret || ret1);
      }

      /// 手机号分服务商
      - (BOOL)q_isValidMobileNumClassification {

      /**
      * 手机号码
      * 移动:134[0-8], 135, 136, 137, 138, 139, 150, 151, 157, 158, 159, 182, 187, 188, 1705
      * 联通:130, 131, 132, 152, 155, 156, 185, 186, 1709
      * 电信:133, 1349, 153, 180, 189, 1700
      */
      // NSString * MOBILE = @"^1((3//d|5[0-35-9]|8[025-9])//d|70[059])\\d{7}$";//总况

      /**
      * 中国移动:China Mobile
      * 134[0-8], 135, 136, 137, 138, 139, 150, 151, 157, 158, 159, 182, 187, 188, 1705
      */
      NSString * CM = @"^1(34[0-8]|(3[5-9]|5[017-9]|8[278])\\d|705)\\d{7}$";

      /**
      * 中国联通:China Unicom
      * 130, 131, 132, 152, 155, 156, 185, 186, 1709
      */
      NSString * CU = @"^1((3[0-2]|5[256]|8[56])\\d|709)\\d{7}$";

      /**
      * 中国电信:China Telecom
      * 133, 1349, 153, 180, 189, 1700
      */
      NSString * CT = @"^1((33|53|8[09])\\d|349|700)\\d{7}$";

      /**
      * 大陆地区固话及小灵通
      * 区号:010, 020, 021, 022, 023, 024, 025, 027, 028, 029
      * 号码:七位或八位
      */
      NSString * PHS = @"^0(10|2[0-5789]|\\d{3})\\d{7,8}$";

      if (([self q_isValidateByRegex:CM]) ||
      ([self q_isValidateByRegex:CU]) ||
      ([self q_isValidateByRegex:CT]) ||
      ([self q_isValidateByRegex:PHS]))
      {
      return YES;
      } else {
      return NO;
      }
      }

      /// 邮箱
      - (BOOL)q_isValidEmailAddress {

      NSString *emailRegex = @"[A-Za-z0-9._%+-]+@[A-Za-z0-9.-]+\\.[A-Za-z]{2,4}";
      return [self q_isValidateByRegex:emailRegex];
      }

      /// 邮编
      - (BOOL)q_isValidPostalcode {

      NSString *postalRegex = @"^[0-8]\\d{5}(?!\\d)$";
      return [self q_isValidateByRegex:postalRegex];
      }

      /// 车牌号
      - (BOOL)q_isValidCarNum {

      // 车牌号:湘K-DE829 香港车牌号码:粤Z-J499港
      // 其中 \u4e00-\u9fa5 表示 unicode 编码中汉字已编码部分,\u9fa5-\u9fff 是保留部分,将来可能会添加
      NSString *carRegex = @"^[\u4e00-\u9fff]{1}[a-zA-Z]{1}[-][a-zA-Z_0-9]{4}[a-zA-Z_0-9_\u4e00-\u9fff]$";
      return [self q_isValidateByRegex:carRegex];
      }

      /// 中文
      - (BOOL)q_isValidChinese {

      NSString *chineseRegex = @"^[\u4e00-\u9fa5]+$";
      return [self q_isValidateByRegex:chineseRegex];
      }

      /// Mac 地址
      - (BOOL)q_isValidMacAddress {

      NSString * macAddRegex = @"([A-Fa-f\\d]{2}:){5}[A-Fa-f\\d]{2}";
      return [self q_isValidateByRegex:macAddRegex];
      }

      /// Url 地址
      - (BOOL)q_isValidUrlAddress {

      NSString *regex = @"^((http)|(https))+:[^\\s]+\\.[^\\s]*$";
      return [self q_isValidateByRegex:regex];
      }

      /// IP 地址
      - (BOOL)q_isValidIPAddress {

      NSString *regex = [NSString stringWithFormat:@"^(\\d{1,3})\\.(\\d{1,3})\\.(\\d{1,3})\\.(\\d{1,3})$"];
      BOOL rc = [self q_isValidateByRegex:regex];

      if (rc) {
      NSArray *componds = [self componentsSeparatedByString:@","];

      BOOL v = YES;
      for (NSString *s in componds) {
      if (s.integerValue > 255) {
      v = NO;
      break;
      }
      }
      return v;
      }
      return NO;
      }

      /// 简单的身份证号码有效性检测
      - (BOOL)q_isSimpleVerifyIdentityCardNum {

      NSString *regex2 = @"^(\\d{14}|\\d{17})(\\d|[xX])$";
      return [self q_isValidateByRegex:regex2];
      }

      /// 精确的身份证号码有效性检测
      - (BOOL)q_isAccurateVerifyIdentityCardNum {

      NSString *value = [self stringByTrimmingCharactersInSet:[NSCharacterSet whitespaceAndNewlineCharacterSet]];

      int length =0;
      if (!value) {
      return NO;
      } else {
      length = (int)value.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 = [value 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 = [value 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:value
      options:NSMatchingReportProgress
      range:NSMakeRange(0, value.length)];

      if (numberofMatch >0) {
      return YES;
      } else {
      return NO;
      }
      case 18:
      year = [value 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:value
      options:NSMatchingReportProgress
      range:NSMakeRange(0, value.length)];

      if (numberofMatch > 0) {
      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;
      int Y = S % 11;
      NSString *M =@"F";
      NSString *JYM =@"10X98765432";
      M = [JYM substringWithRange:NSMakeRange(Y,1)]; // 判断校验位
      if ([M isEqualToString:[value substringWithRange:NSMakeRange(17,1)]]) {
      return YES; // 检测 ID 的校验位
      } else {
      return NO;
      }

      } else {
      return NO;
      }
      default:
      return NO;
      }
      }

      /// 银行卡号
      - (BOOL)q_isValidBankCardNum {

      /** 银行卡号有效性问题Luhn算法
      * 现行 16 位银联卡现行卡号开头 6 位是 622126~622925 之间的,7 到 15 位是银行自定义的,
      * 可能是发卡分行,发卡网点,发卡序号,第 16 位是校验码。
      * 16 位卡号校验位采用 Luhm 校验方法计算:
      * 1,将未带校验位的 15 位卡号从右依次编号 1 到 15,位于奇数位号上的数字乘以 2
      * 2,将奇位乘积的个十位全部相加,再加上所有偶数位上的数字
      * 3,将加法和加上校验位能被 10 整除。
      */

      // 取出最后一位
      NSString * lastNum = [[self substringFromIndex:(self.length-1)] copy];

      // 前 15 或 18 位
      NSString * forwardNum = [[self substringToIndex:(self.length -1)] copy];

      NSMutableArray * forwardArr = [[NSMutableArray alloc] initWithCapacity:0];
      for (int i=0; i<forwardNum.length; i++) {
      NSString * subStr = [forwardNum substringWithRange:NSMakeRange(i, 1)];
      [forwardArr addObject:subStr];
      }

      NSMutableArray * forwardDescArr = [[NSMutableArray alloc] initWithCapacity:0];

      // 前 15 位或者前 18 位倒序存进数组
      for (int i = (int)(forwardArr.count-1); i> -1; i--) {
      [forwardDescArr addObject:forwardArr[i]];
      }

      // 奇数位 *2 的积 < 9
      NSMutableArray * arrOddNum = [[NSMutableArray alloc] initWithCapacity:0];

      // 奇数位 *2 的积 > 9
      NSMutableArray * arrOddNum2 = [[NSMutableArray alloc] initWithCapacity:0];

      // 偶数位数组
      NSMutableArray * arrEvenNum = [[NSMutableArray alloc] initWithCapacity:0];

      for (int i=0; i< forwardDescArr.count; i++) {
      NSInteger num = [forwardDescArr[i] intValue];
      if (i%2) { // 偶数位
      [arrEvenNum addObject:[NSNumber numberWithInteger:num]];
      } else { // 奇数位
      if (num * 2 < 9) {
      [arrOddNum addObject:[NSNumber numberWithInteger:num * 2]];
      } else {
      NSInteger decadeNum = (num * 2) / 10;
      NSInteger unitNum = (num * 2) % 10;
      [arrOddNum2 addObject:[NSNumber numberWithInteger:unitNum]];
      [arrOddNum2 addObject:[NSNumber numberWithInteger:decadeNum]];
      }
      }
      }

      __block NSInteger sumOddNumTotal = 0;
      [arrOddNum enumerateObjectsUsingBlock:^(NSNumber * obj, NSUInteger idx, BOOL *stop) {
      sumOddNumTotal += [obj integerValue];
      }];

      __block NSInteger sumOddNum2Total = 0;
      [arrOddNum2 enumerateObjectsUsingBlock:^(NSNumber * obj, NSUInteger idx, BOOL *stop) {
      sumOddNum2Total += [obj integerValue];
      }];

      __block NSInteger sumEvenNumTotal =0 ;
      [arrEvenNum enumerateObjectsUsingBlock:^(NSNumber * obj, NSUInteger idx, BOOL *stop) {
      sumEvenNumTotal += [obj integerValue];
      }];

      NSInteger lastNumber = [lastNum integerValue];

      NSInteger luhmTotal = lastNumber + sumEvenNumTotal + sumOddNum2Total + sumOddNumTotal;

      return (luhmTotal%10 ==0) ? YES : NO;
      }

      /// 税号
      - (BOOL)q_isValidTaxNum {

      NSString *taxNoRegex = @"[0-9]\\d{13}([0-9]|X)$";
      return [self q_isValidateByRegex:taxNoRegex];
      }

      ///
      - (BOOL)q_isValidWithMinLenth:(NSInteger)minLenth
      maxLenth:(NSInteger)maxLenth
      containChinese:(BOOL)containChinese
      firstCannotBeDigtal:(BOOL)firstCannotBeDigtal {

      // [\u4e00-\u9fa5A-Za-z0-9_]{4,20}
      NSString *hanzi = containChinese ? @"\u4e00-\u9fa5" : @"";
      NSString *first = firstCannotBeDigtal ? @"^[a-zA-Z_]" : @"";

      NSString *regex = [NSString stringWithFormat:@"%@[%@A-Za-z0-9_]{%d,%d}",
      first, hanzi, (int)(minLenth-1), (int)(maxLenth-1)];
      return [self q_isValidateByRegex:regex];
      }

      ///
      - (BOOL)q_isValidWithMinLenth:(NSInteger)minLenth
      maxLenth:(NSInteger)maxLenth
      containChinese:(BOOL)containChinese
      containDigtal:(BOOL)containDigtal
      containLetter:(BOOL)containLetter
      containOtherCharacter:(NSString *)containOtherCharacter
      firstCannotBeDigtal:(BOOL)firstCannotBeDigtal {

      NSString *hanzi = containChinese ? @"\u4e00-\u9fa5" : @"";
      NSString *first = firstCannotBeDigtal ? @"^[a-zA-Z_]" : @"";
      NSString *lengthRegex = [NSString stringWithFormat:@"(?=^.{%@,%@}$)", @(minLenth), @(maxLenth)];
      NSString *digtalRegex = containDigtal ? @"(?=(.*\\d.*){1})" : @"";
      NSString *letterRegex = containLetter ? @"(?=(.*[a-zA-Z].*){1})" : @"";
      NSString *characterRegex = [NSString stringWithFormat:@"(?:%@[%@A-Za-z0-9%@]+)",
      first, hanzi, containOtherCharacter ? containOtherCharacter : @""];
      NSString *regex = [NSString stringWithFormat:@"%@%@%@%@", lengthRegex, digtalRegex, letterRegex, characterRegex];
      return [self q_isValidateByRegex:regex];
      }

      #pragma mark - 助手方法

      /**
      * 判断指定字符串是否匹配规则
      *
      * @param regex
      *
      * @return 返回是否匹配结果
      */
      - (BOOL)q_isValidateByRegex:(NSString *)regex {
      NSPredicate *predicate = [NSPredicate predicateWithFormat:@"SELF MATCHES %@", regex];
      return [predicate evaluateWithObject:self];
      }

      @end
    • ViewController.m

      1
      2
      3
      4
      5
      6
      7
      8
      9
      10
      11
      12
      13
      14
      15
      16
      17
      18
      19
      // 验证手机号码的有效性

      NSString *mobileNum1 = @"15188886666";
      BOOL isValidMobileNum1 = [mobileNum1 q_isValidMobileNum];
      NSLog(@"MobileNum1: %zi", isValidMobileNum1);

      NSString *mobileNum2 = @"19188886666";
      BOOL isValidMobileNum2 = [mobileNum2 q_isValidMobileNum];
      NSLog(@"MobileNum2: %zi", isValidMobileNum2);

      // 验证邮箱的有效性

      NSString *emailAddress1 = @"qianchia@icloud.com";
      BOOL isValidEmailAddress1 = [emailAddress1 q_isValidEmailAddress];
      NSLog(@"EmailAddress1: %zi", isValidEmailAddress1);

      NSString *emailAddress2 = @"qian@chia@icloud.com";
      BOOL isValidEmailAddress2 = [emailAddress2 q_isValidEmailAddress];
      NSLog(@"EmailAddress2: %zi", isValidEmailAddress2);

4.2 简单示例

  • 简单示例

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    37
    38
    39
    40
    41
    42
    43
    - (void)touchesBegan:(NSSet<UITouch *> *)touches withEvent:(UIEvent *)event {

    NSString *str = @"@jack12:【动物尖叫合辑】#肥猪流#猫头鹰这么尖叫[偷笑]、@船长: 老鼠这么尖叫、兔子这么尖叫[吃惊]、
    @花满楼: 莫名奇#小笼包#妙的笑到最后[好爱哦]!~ http://www.jianshu.com 电话: 17334332342";

    // 1.匹配 @ 名字:
    // NSString *pattern = @"@.*?:";

    // 2.匹配 URL
    // NSString *pattern = @"http(s)?://([\\w-]+\\.)+[\\w-]+(/[\\w- ./?%&=]*)?";

    // 3.匹配话题 #....#
    // NSString *pattern = @"#.*?#";

    // 4.手机号码匹配
    NSString *pattern = @"1[3578]\\d{9}$";

    NSError *error = nil;
    /*
    typedef NS_OPTIONS(NSUInteger, NSRegularExpressionOptions) {
    NSRegularExpressionCaseInsensitive = 1 << 0, // 不区分字母大小写的模式
    NSRegularExpressionAllowCommentsAndWhitespace = 1 << 1, // 忽略掉正则表达式中的空格和#号之后的字符
    NSRegularExpressionIgnoreMetacharacters = 1 << 2, // 将正则表达式整体作为字符串处理
    NSRegularExpressionDotMatchesLineSeparators = 1 << 3, // 允许.匹配任何字符,包括换行符
    NSRegularExpressionAnchorsMatchLines = 1 << 4, // 允许^和$符号匹配行的开头和结尾
    NSRegularExpressionUseUnixLineSeparators = 1 << 5, // 设置\n为唯一的行分隔符,否则所有的都有效。
    NSRegularExpressionUseUnicodeWordBoundaries = 1 << 6 // 使用 Unicode TR#29 标准作为词的边界,否则所有传统正则表达式的词边界都有效
    };
    */
    NSRegularExpression *regex = [NSRegularExpression regularExpressionWithPattern:pattern
    options:NSRegularExpressionCaseInsensitive
    error:&error];

    NSArray<NSTextCheckingResult *> *result = [regex matchesInString:str options:0 range:NSMakeRange(0, str.length)];
    if (result) {
    for (int i = 0; i<result.count; i++) {
    NSTextCheckingResult *res = result[i];
    NSLog(@"str == %@", [str substringWithRange:res.range]);
    }
    } else {
    NSLog(@"error == %@",error.description);
    }
    }
文章目录
  1. 1. 1、Regex
  2. 2. 2、语法介绍
  3. 3. 3、常用的正则表达式
  4. 4. 4、正则表达式的使用
    1. 4.1. 4.1 正则表达式使用
    2. 4.2. 4.2 简单示例
隐藏目录