正则表达式:是处理字符串的一种表达方式,提供了一种从一组字符串中选择特定字符串的机制
POSIX规范定义了 UNIX 操作系统支持的功能,POSIX 规范的正则表达式
有两种:
- BRE (Basic Regular Expression) -- 基本型正则表达式
- ERE (Extended Regular Expression) -- 扩展型正则表达式
这里需要注意一点:正则表达式
和通配符
没有任何关系,不是包含关系
1、通配符
是Shell
提供的功能
2、正则表达式
只是用来处理字符串
下面我们来看一个常见的正则表达式
,手机号码的判断:
^1[3-9](\d{9})$
-
^
:锚点操作符,匹配字符串的开头,这里紧跟着1
表示以1
开头的字符串 -
[]
:列表操作符,只匹配中括号中的一个字符 -
-
:范围操作符,指定的范围。3-9
表示范围在3和9之间 -
\d
:代表0-9
之间的数字 -
{}
:间隔运算符,匹配前一个元素N次,这里表示匹配前一个元素9次 -
$
锚点操作符,匹配字符串的结尾
字符匹配
- 我们先来看一些常见的字符
字符 | 描述 |
---|---|
[ABC] |
匹配[...] 中的所有字符,例:[qaz] 匹配字符串"Tiktok Byte Dance"中所有的q a z 字母 |
[^ABC] |
匹配除了[...] 中字符的所有字符,与 [ABC] 相反 |
[A-Z] |
[A-Z] 表示一个区间,匹配所有大写字母,[a-z] 表示所有小写字母 |
. |
匹配所有字符,除了\n \r 和null(空字符),相当于[^\n\r] |
\w | 匹配字母、数字、下划线。等价于[A-Za-z0-9] |
- 重复操作符
字符 | 描述 |
---|---|
* |
匹配前一个元素 0 次 或 多次 |
+ |
匹配前一个元素 1 次 或 多次 |
? |
匹配前一个元素 0 次 或 1次 |
- 间隔操作符
字符 | 描述 |
---|---|
{N} |
匹配前一个元素 N 次,N是一个非负整数 |
{min,} |
匹配前一个元素至少 min 次,min是一个非负整数 |
{min,max} |
匹配前一个元素至少 min 次,至多 max 次;min和max均为非负整数,注意逗号和两个数之间不能有空格
|
-
列表操作符
[...]
&[^...]
一般操作符在列表操作符
里会失去特殊意义,除了:
字符 | 描述 |
---|---|
] |
结束列表[]]
|
\ |
转义字符 |
[: |
字符类别操作符开始 |
:] |
字符类别操作符结束 |
- |
范围操作符,如0-9
|
- 字符类别操作符
字符 | 匹配类型 | 描述 |
---|---|---|
[:alnum:] |
[A-Za-z0-9] | 匹配数字和字母 |
[:alpha:] |
[A-Za-z] | 匹配字母 |
[:blank:] |
[\t] | 匹配空格 和 Tab |
[:cntrl:] |
[\x00-\x1F\x7F] | 匹配控制符 |
[:digit:] |
[0-9] | 匹配数字 |
[:graph:] |
\x21-\x7E | 匹配可视字符 |
[:lower:] |
[a-z] | 匹配小写字母 |
[:print:] |
[\x20-\x7E] | 匹配可视字符和空格 |
[:punct:] |
][!"#$%&'()*+,./:;<=>?@^_`{}·~-] | 匹配标点符号 |
[:space:] |
[\t\r\n\v\f] | 空白字符 |
[:upper:] |
[A-Z] | 匹配大写字母字符 |
[:xdigit:] |
[A-Fa-f0-9] | 匹配十六进制字符 |
- 特殊类别操作符
字符 | 匹配类型 | 描述 |
---|---|---|
\w |
[:alnum:] | 匹配数字和字母 |
\d |
[:digit:] | 匹配数字 |
\W |
[^[:alnum:]] | 匹配除了数字和字母 |
\B |
[^[:digit:]] | 匹配除了数字 |
\< |
^ | 匹配字符串的开头 |
\> |
$ | 匹配字符串的结尾 |
\b |
匹配单词边界字符,to\b,但是不匹配tomorrow |
- 锚点操作符
字符 | 描述 |
---|---|
^ |
匹配字符串的开头,需在开头 |
$ |
匹配字符串的结尾 或 换行符的前一个位置,需在结尾 |
⚠️ 注意:如果^
在列表操作符中使用,并且在首位,代表取反
操作符的优先级
优先级(由高到低) | 操作符 |
---|---|
归类相关的括号符号 | [::] |
转义字符 | \<特殊字符> |
括号表达 | [] |
分组 | () |
单字符重复 |
* + ? {m,n}
|
串联 | . |
锚点 |
^ $
|
备选 | 竖线(Markdown语法冲突,无法描述) |
贪婪模式、勉强模式、侵占模式
贪婪匹配 | 勉强匹配 | 侵占匹配 | 描述 |
---|---|---|---|
X? |
X?? |
X?+ |
匹配X 零次或一次 |
X* |
X*? |
X*+ |
匹配X 零次或多次 |
X+ |
X+? |
X++ |
匹配X 一次或多次 |
X{n} |
X{n}? |
X{n}+ |
匹配X n次 |
X{n,} |
X{n,}? |
X{n,}+ |
匹配X 至少n次 |
X{n,m} |
X{n,m}? |
X{n,m}+ |
匹配X 至少n次,但不超过m次 |
贪婪模式
例子:GoogleMaps
- 模式:
.*aps
(贪婪模式) 由两部分组成
1、p1(.*
) :匹配方式为贪婪型
2、p2(aps
)
匹配开始: - 第一轮:
首先,p1会匹配字符串中的所有字符GoogleMaps
,匹配成功;但是p2没有匹配字符,本轮匹配失败。 - 第二轮:
减少p1的匹配量,留出最后一个字符,那么此时存在两个字符串:s1代表GoogleMap
/ s2代表s
。此时s1匹配p1,但是s2不匹配p2,本轮匹配失败。 - 第三轮:
继续减少p1的匹配量,留出两个字符,结果同第二轮一样。 - 第四轮:
再次减少p1的匹配量,字符串被分割成GoogleM
和aps
两个部分,此时p1和p2都能匹配。返回匹配成功。
勉强模式
例子:GoogleMaps
- 模式:
.*?aps
(勉强模式) 最小匹配方式,同样的分为两部分
1、p1(.*?
) :匹配方式为勉强模式
2、p2(aps
)
匹配开始: - 第一轮:p1由于是0次和任意次,首次匹配0次;则直接用字符串去匹配p2,但是p2无法匹配字符,本轮匹配失败。
- 第二轮:
增加p1的匹配量,匹配G
;此时存在两个字符串,s1代表G
/ s2代表oogleMaps
,s1匹配p1,但是s2不匹配p2,本轮匹配失败。
继续上述匹配,直到满足p2
侵占模式
例子:`GoogleMaps
- 模式:
.*+aps
(侵占模式) ,同样的分为两部分
1、p1(.*+
) :匹配方式为勉强模式
2、p2(aps
)
匹配开始时读入所有字符串,和p1匹配成功;但没有剩余字符串去和p2匹配,匹配失败。
简单讲,贪婪模式和侵占模式相比,
1、贪婪模式会在只有部分匹配成功的条件下,依次从多到少,减少匹配成功部分的匹配量,将字符留给其他部分去匹配
2、而侵占模式则是占有所有能匹配成功的部分,绝不留给其他部分使用
iOS中正则表达式的应用
NSString *phoneNum = @"1384587921";
NSError *error = NULL;
NSRegularExpression *regex = [NSRegularExpression regularExpressionWithPattern:@"^1[3-9]([:digit:]{9})$" options:NSRegularExpressionCaseInsensitive error:&error];
NSTextCheckingResult *result = [regex firstMatchInString:phoneNum options:0 range:NSMakeRange(0, [phoneNum length])];
if (result) {
NSLog(@"匹配成功");
} else {
NSLog(@"匹配失败");
}
⚠️⚠️⚠️ 注意:正则表达式在不同的开发环境中是有所区别的,这一点需要在实际开发中灵活应用,比如:
在iOS的环境下,
\d
是不识别的。这是因为OC 和 Swift 都要求 转义文字字符串中的特殊字符(即:在它们前面加上
反斜杠\
)。反斜杠本身就是这样的特殊字符之一,由于用于创建正则表达式的模式也是字符串,因此会增加复杂性,因为在使用Stingand时需要转义反斜杠字符NSRegularWxpression。
这也就意味着标准正则表达式\d
,将以\\d
的形式出现在Swift 或 OC 代码中。这一点大家要注意!
^1[3-9](\\d{9})$
参考文档:正则表达式 - 语法