Regular Expression

正则表达式

1. 简介

正则表达式 ( Regular Expression 通常简写成 regexp 或 RE)是一个工具,本质上也是一门语言;诞生于贝尔实验室

正则表达式 使用单个字符串来描述、匹配一系列 匹配某个句法规则的字符串

简单来讲:它用一个“ 字符串” 来描述一个特征,然后去验证另一个“字符串”是否符合这个特征

正则表达式 通常被用来检索、替换那些匹配某个模式的文本

诸如以下场景:

  • 假如你要搜索一个文件,这个文件里包含了单词 ‘cat ’(不区分字母大小写)

    而且你并不想把包含着 ‘cat ’ 的其它单词(比如 catch 、cattle 等)也找出来

  • 假如你的 web 服务器接收从表单发送过来的用户邮箱地址信息

    你需要检查电子邮件地址是否符合正确的语法格式

  • 假如你正在编辑一段源代码并且要把所有的 ‘size’ 都替换成 ‘issize’

    而且这种替换仅限于 ‘size’ 单词本身,而不涉及那些包含着字符串 ‘size’的其它单词

  • 假如你需要在文件里搜索某个特定的文本

    而且你只想把出现在特定位置的,比如每一行的开头或结尾找出来

以上场景通常会出现在程序编写的过程中

当然我们可以利用支持条件处理和字符串操作的编程语言解决它们

但是这样的效率低下,并不推荐

上述问题都可以通过精心构造一些匹配表达式或一些由文本和特殊字符串构成的高度简练的字符串来解决

其它简介:

  1. 大多数编程语言内部都集成了正则引擎,并非某一语言特有
  2. 正则表达式是业界公认的字符串匹配工具,可移植性强
  3. 正则表达式默认是从左往右匹配
  4. 正则表达式默认是贪婪模式(优先取上限,而非下限)
  5. 正则表达式默认一旦匹配到内容后,便终止匹配
  6. 正则表达式对于同一问题,可有多种表现形式,并不唯一
  7. 正则表达式的所有字符均为英文半角字符

2. 语法

/pattern/modifiers;
/* 此语法结构针对javascript 即 "模型/修饰符" */

/* 例如在javascript中的实例 */
var patt= /venusoooooo/i;
/* veunsoooooo是模式(在搜索中使用);i是修饰符表示搜索结果对大小写不敏感*/

1. 普通字符

字母、数字 、汉字、下划线以及没有特殊定义的符号 都是 “普通字符”

正则表达式中的普通字符,在匹配的时候,只匹配与自身相同的一个字符

例如:

表达式 c ,在匹配字符串 abcde

匹配结果:成功

匹配内容为 c

匹配位置开始于2,结束于3(索引下标是从0开始还是从1开始,取决于当前编程语言,JavaScript开始于0)

2. 元字符

正则表达式中使用了很多元字符,用来表示一些特殊的含义或功能

元字符 意义
. 除了换行符 \n 以外的任意一个字符(例如 a.c 匹配 abc)
| 逻辑或操作符 (例如 (a|b)c 匹配 ac或 bc )
[ ] 匹配字符集中的任意一个字符 (例如 [abc]1 匹配 a1或 b1 或 c1 )
[ ^ ] 对字符集求反,上面的反向操作(注意上标符号必须在方括号里的最前面)
- 定义在 [ ] 里的一个字符区间(例如 [a-z] ;表示 a,b,c,d……z中26个字符的任一字符)
\ 对紧跟其后的一个字符进行转义
() 对表达式分组,将圆括号内的内容当做一个整体,并获得匹配的值
\uxxxx 匹配以十六进制数xxxx规定的 Unicode字符
\xxx 匹配以八进制数xxx 规定的字符
\xdd 匹配以十六进制数dd规定的字符
^ 匹配字符开头
$ 匹配字符结尾

3. 转义字符

一些无法书写或具有特殊功能的字符,采用在前面加斜杠 “ \ ” 进行转义,以表达其自身真实的含义

转义字符 意义
\n 匹配一个换行符;等价于 \x0c 和 \cJ
\r 匹配一个回车符;等价于 \x0d 和 \cM
\t 匹配一个制表符; 等价于 \x09 和 \cl
\d 匹配一个数字字符; 等价于 [0-9]
\D 匹配一个非数字字符; 等价于[^ 0-9 ]
\v 匹配一个垂直制表符; 等价于 \x0b 和 \cK
\s 匹配任意一个空白字符,包括空格、制表符、换页符等 等价于 [\f\n\r\t\v]
\S 匹配任何非空白字符; 等价于 [^ \f\n\r\t\v]
\f 匹配一个换页符; 等价于 \x0c 和 \cL
\w 匹配任意一个字母、数字、下划线; 等价于 [A-Za-z0-9]
\W 匹配非字母、数字、下划线; 等价于[^ A-Za-z0-9]
\b 匹配一个单词的边界,即单词和空格间的的位置 (例如 ‘er\b’ 可以匹配 “never” 中的 ’er’ )
\B 匹配非单词边界 (例如 ‘er\B’ 能匹配 “verb”中的 ‘er’ )
\. 匹配小数点 . 本身
\\ 匹配斜杠 \ 本身
\^ 匹配上标符号 ^ 本身
\$ 匹配 $ 符号本身
\? 匹配 问号 ? 本身
\* 匹配 星号 * 本身
\( ) 匹配括号 ( ) 本身

4. 量词

量词表示要匹配的字符或表达式的数量

Greedy Reluctant Possessive 意义
X{n} X{n}? X{n}+ 匹配 X n 次(例如 a{2} ,匹配 aa)(这种不存在模式划分)
X X{m,}? X{m,}+ 匹配 X m-∞ 次,优先匹配∞次(例如 a{1,} 可以匹配 aaaaa……)
X X{m,n}? X{m,n}+ 匹配 X m-n 次,优先匹配 n 次 (例如 a{1,3} 可以匹配 aaa,aa,a)
X? X?? X?+ 匹配 X 0 次或 1 次,优先匹配1次, 等价于
X+ X+? X++ 匹配 X 1-n 次,优先匹配 n 次,等价于
X* X*? X*+ 匹配 X 0-n 次 ,优先匹配 n 次,等价于

注意:

ab{1,3} 匹配 abb ;重复匹配的是b而不是ab

(ab){1,3} 匹配 ababab;()为一个整体,重复匹配的是ab

3. 匹配模式

正则表达式有3种模式,分别为 Greedy (贪婪) 、Reluctant (勉强) 、Possessive (侵占)

区别分析:

假如要分析的字符串是 xfooxxxxxxfoo

Greedy 模式:

模式 . foo* 分为子模式 p1 (.*) 和 子模式 p2 (foo) 两个部分,其中 p1 中的量词匹配方式使用默认方式(贪婪型)

匹配开始时:读入所有字符 xfooxxxxxxfoo 去匹配模式p1 ;匹配成功,但这样以来没有了字符串去匹配 子模式 p2 ;本轮匹配失败

第二轮:减少p1 部分的匹配量,读出最后1个字符,把字符串分割成 xfooxxxxxxfo 和 o 两个子字符串 s1 和 s2

s1匹配p1 , s2 不匹配 p2,本轮匹配失败

第三轮:再次减少p1 部分的匹配量,读出最后2个字符,字符串被分割成 xfooxxxxxxf 和 oo 两个字符串 s1和 s2 ,结果同上

第四轮:再次减少p1 部分的匹配量,读出最后3个字符,字符串被分割成 xfooxxxxxx 和 foo 两个字符串 s1 和 s2

这次 s1 匹配 p1 ,s2 匹配 p2 停止尝试,返回 xfoo ;匹配成功

Reluctant 模式:

最小匹配方式

第一轮尝试匹配, p1 由于是 0 或任意次,因此被忽略,用字符串去 匹配 p2 失败

第二轮,读入第一个字符 x ,尝试和 p1 匹配,匹配成功 ;字符串剩余部分 fooxxxxxxfoo 中前三个字符和 p2 也是匹配的

因此停止尝试,返回 xfoo ; 匹配成功

在这种模式下,如果对剩余字符串继续寻找和模式相匹配的子字符串,还会找到字符串末尾的另一个 xfoo

而在贪婪模式下,由于第一次匹配成功的子字符串就已经是所有字符,因此不存在第二个匹配子字符串

Possessive 模式:

也叫占用模式

匹配开始时读入所有字符串,和 P1 匹配成功,但没有生育字符串去和 p2 匹配,因此匹配失败,返回

  • 贪婪模式和占有模式相比,贪婪模式会在只有部分匹配成功的条件下,依次从多到少减少匹配成功部分模式的匹配数量,将字符留给模式其他部分去匹配

    而占有模式则是占有所有能匹配成功部分,绝不留给其他部分使用

4. 反向引用

表达式在匹配时,表达式引擎会将小括号 ( ) 包含的表达式所匹配到的字符串记录下来

在获取匹配结果的时候,小括号包含的表达式所匹配的字符串可以单独获取

在实际应用场合中,当用某种边界来查找,而所要获取的内容又不包含边界时

必须使用小括号来指定所需要的范围

其实小括号包含的表达式所匹配到的字符串,不仅在匹配结束后可以使用,在匹配过程中也可以使用

表达式后边的部分,可以引用前面 “括号内的子匹配已经匹配到的字符串”

引用方法是 \加上一个数字

例如: \1 引用第1对括号内匹配到的字符串;\2引用第2对括号匹配到的字符串……以此类推

​ 如果一对括号内包含另一对括号,则外层的括号先排序号 (哪一对的左括号在前,那这一对就先排序)

例如:

表达式 (\w)\1{4,} 在匹配 aa bbbb agcdefg ccccc 111121111 9999999999时

首先匹配到的内容是 ccccc

再次匹配下一个是,将得到 9999999999

这个表达式要求 \w 范围的字符至少重复5次

同时注意与 \w{5,}之间的区别

\w{5,} 首先匹配到 9999999999 其次才是 ccccc

5. 常用正则表达式

1. 校验数字的相关表达式

功能 表达式
数字 ^[0-9]*$
n位的数字 ^\d{n}$
至少n位的数字 ^\d{n,}$
m-n位的数字 ^\d{m,n}$
零和非零开头的数字 ^(0|[1-9][0-9]*)$
非零开头最多带两位小数的数字 ^([1-9][0-9]*)+(.[0-9{1,2}])?$
带1-2位小数的正数或负数 ^(\-)?\d+(\.\d{1,2})?$
正数、负数、小数 ^(\-|\+)?\d+(\.\d+)?$
有两位小数的正实数 ^[0-9]+(.[0-9]{2})?$
有1~3位小数的正实数 ^[0-9]+(.[0-9]{1,3})?$
非零的正整数 ^[1-9]\d*$
非零的负整数 ^-[1-9]\d*$
非负整数 ^\d+$
非正整数 ^-[1-9]\d*|0$
非负浮点数 ^\d+(\.\d+)?$
非正浮点数 ^((-\d+(\.\d+)?)|(0+(\.0+)?))$
正浮点数 ^[1-9]\d*\.\d*|0\.\d*[1-9]\d*$
负浮点数 ^-([1-9]\d*\.\d*|0\.\d*[1-9]\d*)$
浮点数 ^(-?\d+)(\.\d+)?$

2. 校验字符的相关表达式

功能 表达式
汉字 ^[\u4e00-\u9fa5]{0,}$
英文和数字 ^[A-Za-z0-9]+$
长度为3-20的所有字符 ^.{3,20}$
由26个英文字母组成的字符串 ^[A-Za-z]+$
由26个大写英文字母组成的字符串 ^[A-Z]+$
由26个小写英文字母组成的字符串 ^[a-z]+$
由数字和26个英文字母组成的字符串 ^[A-Za-z0-9]+$
由数字、26个英文字或下划线组成的字符串 ^\w+$
中文、英文、数字包括下划线 ^[\u4e00-\u9fa5A-Za-z0-9_]+$
中文、英文、数字不包括下划线 ^[\u4e00-\u9fa5A-Za-z0-9]+$
可以输入含有^%&‘,;=?$\"等字符 [^%&‘,;=?$\x22]+
禁止输入含有~的字符 [^~\x22]+

3. 特殊场景的表达式

功能 表达式
Email地址 ^\w+([-+.]\w+)*@\w+([-.]\w+)*\.\w+([-.]\w+)*$
域名 [a-zA-Z0-9][-a-zA-Z0-9]{0,62}(/.[a-zA-Z0-9][-a-zA-Z0-9]{0,62})+/.?
InternetURL [a-zA-Z]+://[^\s]* 或 ^http://([\w-]+\.)+[\w-]+(/[\w-./?%&=]*)?$
手机号码 ^(13[0-9]|14[5|7]|15[0|1|2|3|5|6|7|8|9]|18[0|1|2|3|5|6|7|8|9])\d{8}$
国内电话号码 ^\d{3}-\d{8}|\d{4}-\d{7}$ eg:021-87888822、0511-4405222
身份证号 ^[0-9X]{15}|[0-9X]{18}$ (15或18位数)
账号是否合法 ^[a-zA-Z][a-zA-Z0-9_]{4,15}$ (字母开头,允许5-16字节,允许字母数字下划线)
密码 ^[a-zA-Z]\w{5,17}$ (字母开头,长度在6-18字节,允许字母数字下划线)
强密码 ^(?=.*\d)(?=.*[a-z])(?=.*[A-Z]).{8,10}$ (须包含大小写字母和数字组合,长度在8-10之间)
日期格式 ^\d{4}-\d{1,2}-\d{1,2}$
12个月(年) ^(0?[1-9]|1[0-2])$
^((0?[1-9])|(1|2[0-9])|30|31)$
xml文件 ^([a-zA-Z]+-?)+[a-zA-Z0-9]+\\.[x|X][m|M][l|L]$
双字节字符 [^\x00-\xff] (包括汉字在内,可以用来计算字符串的长度(单双字节计2,单ASCII计1))
空白行的正则 \n\s*\r(可以用来删除空白行)
HTML的正则 <(\S*?)[^>]*>.*?</\1>|<.*? /> (对于复杂的嵌套标记依旧无能为力)
首尾空白字符 ^(\s*)|(\s*)$ (可用来删除行首行尾的空白字符;如空格、制表符、换页符等)
腾讯QQ [1-9][0-9]{4,} (腾讯QQ号从10000开始)
中国邮政编码 [1-9]\d{5}(?!\d) (中国邮政编码为6位数字)
IP地址提取 \d+\.\d+\.\d+\.\d+(提取IP地址时有用)
IP地址合法判断 ((?: (?:25[0-5]|2[0-4])\\d|[01]?\\d?\\d)\\.){3}(?:25[0-5]|2[0-4]\\d|[01]?\\d?\\d)
posted @ 2021-01-19 21:51  Kuiperbelt  阅读(103)  评论(0)    收藏  举报