作者: 张敏;
标签: 正则表达式
正则表达式
前言
一说到正则表达式,估计很多人第一感觉就是难学看不懂。然后就跟我一样一再搁置,放着这个知识点不学。其实很多人感觉难学看不懂是因为正则表达式不像其他的代码易读性比较好,不能一眼看出代码的意思。用的不多的话不理解其语法的话就更加是闻正则色变。本篇将会介绍一些正则的基本用法,帮助更好的理解正则,我也趁此机会接触学习一下正则的基本语法。
知识点
什么是正则表达式?
正则表达式是一种描述字符串结构模式的形式化表达方法,这是《精通正则表达式》对于其的定义(估计很多人看了也不懂什么意思)。以我的理解来说,正则表达式就是定义一种规则去匹配符合该规则的字符。如果有用过通配符的话,可以将正则表达式跟通配符类比,它们都是用来进行文本匹配的工具。不过比起通配符,正则表达式可以更加精确地去匹配你所要匹配的文本,不过需要你编应相应的规则。
为什么要用正则表达式?
- 复杂的字符串搜寻、替换工作,无法用简单的方式(类似借助标准库函数)达成。
- 能够帮助你进行各种字符串验证。
- 不止应用于编程语言中:JavaScript、JAVA、Perl、PHP、C#,也应用于许多操作系统的主流指令中:Linux/Unix、Mac、Windows PowerScript
- 在Python爬虫应用中应用广泛
常用的正则匹配工具
- 在线匹配工具:
- 正则匹配软件
- McTracer
正则字符的简单介绍
-
元字符介绍
元字符 描述 ^ ^会匹配行或者字符串的起始位置,有时还会匹配整个文档的起始位置 $ $会匹配行或字符串的结尾 \b 不会消耗任何字符只匹配一个位置,代表单词的开头和结尾。常用于匹配单词边界。例如你要查找hello这个单词。即为\bhello\b \d 匹配数字 \w 匹配字母,数字,下划线或汉字 \s 匹配空格。例如字符 "a b c" 正则:"\w\s\w\s\w" 一个字符后跟一个空格,如有字符间有多个空格直接把"\s" 写成 "\s+" 让空格重复 . 匹配除了换行符以外的任何字符 [abc] 字符组 匹配包含括号内元素的字符,这个比较简单了只匹配括号内存在的字符,还可以写成[a-z]匹配a至z的所以字母就等于可以用来控制只能输入英文
- 字符的转义
如果想查找的是元字符本身的话,此时你应该使用\转义这些字符,取消这些字符的特殊意义。如果想使用.或*等特殊元字符。这些特殊字符的话可以在其前加个\。如.或*。如果要查找\本身也是如此,\。例如C:\document相当于匹配C:\document。 - 反义
元字符的反义写法很简单,将原来的元字符改成大写就行了,意思与原来的相反- "\W" 匹配任意不是字母,数字,下划线 的字符
- "\S" 匹配任意不是空白符的字符
- "\D" 匹配任意非数字的字符
- "\B" 匹配不是单词开头或结束的位置
- "[^abc]" 匹配除了abc以外的任意字符
- 量词
先解释关于量词所涉及到的重要的三个概念:
- 贪婪(贪心)
如"*"字符,贪婪量词会首先匹配整个字符串,尝试匹配时,它会选定尽可能多的内容,如果失败则回退一个字符,然后再次尝试回退的过程就叫做回溯,它会每次回退一个字符,直到找到匹配的内容或者没有字符可以回退。相比下面两种贪婪量词对资源的消耗是最大的
- 懒惰(勉强)
如 "?" ,懒惰量词使用另一种方式匹配,它从目标的起始位置开始尝试匹配,每次检查一个字符,并寻找它要匹配的内容,如此循环直到字符结尾处。
- 占有
如"+" 占有量词会覆盖事个目标字符串,然后尝试寻找匹配内容 ,但它只尝试一次,不会回溯
语法 | 描述 |
---|---|
* | (贪婪)重复零次或更多; 例如"aaaaaaaa" 匹配字符串中所有的a 正则: "a*" 会出到所有的字符"a" |
+ | (占有)重复一次或更多次; 例如"aaaaaaaa" 匹配字符串中所有的a 正则: "a+" 会取到字符中所有的a字符, "a+"与"a"不同在于"+"至少是一次而"" 可以是0次 |
? | (懒惰)重复零次或一次; 例如"aaaaaaaa" 匹配字符串中的a 正则 : "a?" 只会匹配一次,也就是结果只是单个字符a |
{n} | 重复n次; 例如从"aaaaaaaa" 匹配字符串的a 并重复3次 正则: "a{3}" 结果就是取到3个a字符 "aaa"; |
{n,m} | 重复n到m次; 例如正则 "a{3,4}" 将a重复匹配3次或者4次 所以供匹配的字符可以是三个"aaa"也可以是四个"aaaa" 正则都可以匹配到 |
{n,} | 重复n次或更多次; |
- 懒惰限定符
-
"*?" 重复任意次,但尽可能少重复
如 "acbacb" 正则 "a.*?b" 只会取到第一个"acb" 原本可以全部取到但加了限定符后,只会匹配尽可能少的字符 ,而"acbacb"最少字符的结果就是"acb"
-
"+?" 重复1次或更多次,但尽可能少重复
与上面一样,只是至少要重复1次
-
"??" 重复0次或1次,但尽可能少重复
如 "aaacb" 正则 "a.??b" 只会取到最后的三个字符"acb"
-
"{n,m}?" 重复n到m次,但尽可能少重复
如 "aaaaaaaa" 正则 "a{0,m}" 因为最少是0次所以取到结果为空
-
"{n,}?" 重复n次以上,但尽可能少重复
如 "aaaaaaa" 正则 "a{1,}" 最少是1次所以取到结果为 "a"
-
正则进阶
-
捕获分组
使用小括号指定一个子表达式后,匹配这个子表达式的文本(也就是此分组捕获的内容)可以在表达式或其它程序中作进一步的处理。默认情况下,每个分组会自动拥有一个组号,规则是:从左向右,以分组的左括号为标志,第一个出现的分组的组号为1,第二个为2,以此类推。分组0对应整个正则表达式。
后向引用用于重复搜索前面某个分组匹配的文本。例如,\1代表分组1匹配的文本。
示例:
\b(\w+)\b\s+\1\b可以用来匹配重复的单词,像go go, 或者kitty kitty。这个表达式首先是一个单词,也就是单词开始处和结束处之间的多于一个的字母或数字(\b(\w+)\b),这个单词会被捕获到编号为1的分组中,然后是1个或几个空白符(\s+),最后是分组1中捕获的内容(也就是前面匹配的那个单词)(\1)。
你也可以自定义子表达式的组名。要指定一个子表达式的组名,语法如下:
(?<Word>\w+)(或者把尖括号换成'也行:(?'Word'\w+)),这样就把\w+的组名指定为Word了。要反向引用这个分组捕获的内容,你可以使用\k<Word>,所以上一个例子也可以写成这样:\b(?<Word>\w+)\b\s+\k<Word>\b。
以下是捕获分组的常用的用法:
语法 描述 (exp) 匹配exp,并捕获文本到自动命名的组里 (?<name>exp) 匹配exp,并捕获文本到名称为name的组里 (?:exp) 匹配exp,不捕获匹配的文本,也不给此分组分配组号 以下为零宽断言用法:
语法 描述 (?=exp) 匹配exp前面的位置;如 "How are you doing" 正则"(?<txt>.+(?=ing))" 这里取ing前所有的字符,并定义了一个捕获分组名字为 "txt" 而"txt"这个组里的值为"How are you do"; (?<=exp) 匹配exp后面的位置;如 "How are you doing" 正则"(?<txt>(?<=How).+)" 这里取"How"之后所有的字符,并定义了一个捕获分组名字为 "txt" 而"txt"这个组里的值为" are you doing" (?!exp) 匹配后面跟的不是exp的位置;如 "123abc" 正则 "\d{3}(?!\d)"匹配3位数字后非数字的结果 (?<!exp) 匹配前面不是exp的位置;如 "abc123 " 正则 "(?<![0-9])123" 匹配"123"前面是非数字的结果也可写成"(?!<\d)123"
-
分支条件
正则表达式里的分枝条件指的是有几种匹配规则,如果满足其中任意一种规则都应该当成匹配,具体方法是用|把不同的规则分隔开例如:
0\d{2}-\d{8}|0\d{3}-\d{7}这个表达式能匹配两种以连字号分隔的电话号码:一种是三位区号,8位本地号(如010-12345678),一种是4位区号,7位本地号(0753-6816488)。
应用场景
- 验证密码长度是否符合要求
如: 判断密码长度是否在6-18位之间 ^.{6,18}$ - 固定电话
如: 匹配一种是三位区号,8位本地号(如010-12345678),一种是4位区号,7位本地号(0753-6816488)。0\d{2}-\d{8}|0\d{3}-\d{7} - 校验网址
[a-zA-z]+://[^\s]*
以上是几种应用场景,主要是用来校验相关字段,在下一篇正则在javascript的应用中还会提到。
总结
正则的语法是很多,也很让人头疼。同一种规则也会有不同的写法,要征服正则的第一步就是自己多写多练多使用,这样才能进一步的熟练正则。以上只是简单的介绍了正则的一些用法,还有很多没有提到,有兴趣可以找相关资料进一步学习。