正则表达式必知必会

基本概念
正则表达式描述了一种字符串匹配的文字模式,由普通字符(例如字符 a 到 z)以及特殊字符(称为元字符)组成,将该模式与所搜索的字符串进行匹配。
通俗的讲,正则表达式至关于定义了一个模板,从某个字符串中按照这个模板进行某种。好比检查是否含有某种子字符串,将匹配的子字符串作替换,从某个字符串中取出符合条件的子字符串等。php

 

字符组成
正则表达式是由普通字符(例如字符 a 到 z)以及特殊字符(称为元字符)组成的文字模式。html

普通字符java

由全部那些未显式指定为元字符的打印和非打印字符组成。这包括全部的大写和小写字母字符,全部数字,全部标点符号以及一些符号。jquery

非打印字符git

字符 含义
\cx 匹配由x指明的控制字符。例如, \cM 匹配一个 Control-M 或回车符。x 的值必须为 A-Z 或 a-z 之一。不然,将 c 视为一个原义的 'c' 字符。
\f 匹配一个换页符。等价于 \x0c 和 \cL。
\n 匹配一个换行符。等价于 \x0a 和 \cJ。
\r 匹配一个回车符。等价于 \x0d 和 \cM。
\s 匹配任何空白字符,包括空格、制表符、换页符等等。等价于 [ \f\n\r\t\v]。
\S 匹配任何非空白字符。等价于 [^ \f\n\r\t\v]。
\t 匹配一个制表符。等价于 \x09 和 \cI。
\v 匹配一个垂直制表符。等价于 \x0b 和 \cK。

 

 

 

 

 

 

 

特殊字符正则表达式

所谓特殊字符,就是一些有特殊含义的字符,如上面说的"*.txt"中的*,简单的说就是表示任何字符串的意思。若是要查找文件名中有*的文件,则须要对*进行转义,即在其前加一个\。ls \*.txt。正则表达式有如下特殊字符。api

特备字符 说明
$ 匹配输入字符串的结尾位置。若是设置了 RegExp 对象的 Multiline 属性,则 $ 也匹配 '\n' 或 '\r'。要匹配 $ 字符自己,请使用 \$
() 标记一个子表达式的开始和结束位置。子表达式能够获取供之后使用。要匹配这些字符,请使用 \( 和 \)
* 匹配前面的子表达式零次或屡次。要匹配 * 字符,请使用 \*
+ 匹配前面的子表达式一次或屡次。要匹配 + 字符,请使用 \+
. 匹配除换行符 \n以外的任何单字符。要匹配 .,请使用 \
[ 标记一个中括号表达式的开始。要匹配 [,请使用 \[
? 匹配前面的子表达式零次或一次,或指明一个非贪婪限定符。要匹配 ? 字符,请使用 \?
\ 将下一个字符标记为或特殊字符、或原义字符、或向后引用、或八进制转义符。例如, 'n' 匹配字符 'n'。'\n' 匹配换行符。序列 '\\' 匹配 "\",而 '\(' 则匹配 "("
^ 匹配输入字符串的开始位置,除非在方括号表达式中使用,此时它表示不接受该字符集合。要匹配 ^ 字符自己,请使用 \^
{ 标记限定符表达式的开始。要匹配 {,请使用 \{
| 指明两项之间的一个选择。要匹配 |,请使用 \|

限定符
限定符用来指定正则表达式的一个给定组件必需要出现多少次才能知足匹配。有*或+或?或{n}或{n,}或{n,m}共6种。
*、+和?限定符都是贪婪的,由于它们会尽量多的匹配文字,只有在它们的后面加上一个?就能够实现非贪婪或最小匹配。
正则表达式的限定符有:数组

字符 描述
* 匹配前面的子表达式零次或屡次。例如,zo* 能匹配 "z" 以及 "zoo"。* 等价于{0,}
+ 匹配前面的子表达式一次或屡次。例如,'zo+' 能匹配 "zo" 以及 "zoo",但不能匹配 "z"。+ 等价于 {1,}
匹配前面的子表达式零次或一次。例如,"do(es)?" 能够匹配 "do" 或 "does" 中的"do" 。? 等价于 {0,1}
{n} n 是一个非负整数。匹配肯定的 n 次。例如,'o{2}' 不能匹配 "Bob" 中的 'o',可是能匹配 "food" 中的两个 o
{n,} n 是一个非负整数。至少匹配n 次。例如,'o{2,}' 不能匹配 "Bob" 中的 'o',但能匹配 "foooood" 中的全部 o。'o{1,}' 等价于 'o+'。'o{0,}' 则等价于 'o*'
{n,m} m 和 n 均为非负整数,其中n <= m。最少匹配 n 次且最多匹配 m 次。例如,"o{1,3}" 将匹配 "fooooood" 中的前三个 o。'o{0,1}' 等价于 'o?'。请注意在逗号和两个数之间不能有空格

定位符缓存

用来描述字符串或单词的边界,^和$分别指字符串的开始与结束,\b描述单词的前或后边界,\B表示非单词边界。不能对定位符使用限定符。app

选择
用圆括号将全部选择项括起来,相邻的选择项之间用|分隔。但用圆括号会有一个反作用,是相关的匹配会被缓存,此时可用?:放在第一个选项前来消除这种反作用。
其中?:是非捕获元之一,还有两个非捕获元是?=和?!,这两个还有更多的含义,前者为正向预查,在任何开始匹配圆括号内的正则表达式模式的位置来匹配搜索字符串,后者为负向预查,在任何开始不匹配该正则表达式模式的位置来匹配搜索字符串。

后向引用
对一个正则表达式模式或部分模式两边添加圆括号将致使相关匹配存储到一个临时缓冲区中,所捕获的每一个子匹配都按照在正则表达式模式中从左至右所遇到的内容存储。存储子匹配的缓冲区编号从 1 开始,连续编号直至最大 99 个子表达式。每一个缓冲区均可以使用 '\n' 访问,其中 n 为一个标识特定缓冲区的一位或两位十进制数。
可使用非捕获元字符 '?:', '?=', or '?!' 来忽略对相关匹配的保存。

 

运算优先级
相同优先级的从左到右进行运算,不一样优先级的运算先高后低。各类操做符的优先级从高到低以下:

操做符 描述
\ 转义符
(), (?:), (?=), [] 圆括号和方括号
*, +, ?, {n}, {n,}, {n,m} 限定符
^, $, \anymetacharacter 位置和顺序
| “或”操做



 

 

 

 

匹配规则

基本模式匹配
一切从最基本的开始。模式,是正规表达式最基本的元素,它们是一组描述字符串特征的字符。模式能够很简单,由普通的字符串组成,也能够很是复杂,每每用特殊的字符表示一个范围内的字符、重复出现,或表示上下文。例如:

  • ^once:这个模式包含一个特殊的字符^,表示该模式只匹配那些以once开头的字符串。例如该模式与字符串"once upon a time"匹配,与"There once was a man from NewYork"不匹配。正如^符号表示开头同样,$符号用来匹配那些以给定模式结尾的字符串。
  • bucket$:这个模式与"Who kept all of this cash in a bucket"匹配,与"buckets"不匹配。字符^和$同时使用时,表示精确匹配(字符串与模式同样)。

例如:^bucket$只匹配字符串"bucket"。若是一个模式不包括^和$,那么它与任何包含该模式的字符串匹配。

例如:模式once与字符串Who kept all of his cash in a bucket.是匹配的。在该模式中的字母(o-n-c-e)是字面的字符,也就是说,他们表示该字母自己,数字也是同样的。

其余一些稍微复杂的字符,如标点符号和白字符(空格、制表符等),要用到转义序列。全部的转义序列都用反斜杠(\)打头。制表符的转义序列是:\t。因此若是咱们要检测一个字符串是否以制表符开头,能够用这个模式:^\t

相似的,用\n表示“新行”,\r表示回车。其余的特殊符号,能够用在前面加上反斜杠,如反斜杠自己用\\表示,句号.用\.表示,以此类推。

字符簇
在INTERNET的程序中,正规表达式一般用来验证用户的输入。当用户提交一个FORM之后,要判断输入的电话号码、地址、EMAIL地址、信用卡号码等是否有效,用普通的基于字面的字符是不够的。
因此要用一种更自由的描述咱们要的模式的办法,它就是字符簇。要创建一个表示全部元音字符的字符簇,就把全部的元音字符放在一个方括号里:

[AaEeIiOoUu]

这个模式与任何元音字符匹配,但只能表示一个字符。用连字号能够表示一个字符的范围,如:

[a-z] //匹配全部的小写字母 
[A-Z] //匹配全部的大写字母 
[a-zA-Z] //匹配全部的字母 
[0-9] //匹配全部的数字 
[0-9\.\-] //匹配全部的数字,句号和减号 
[ \f\r\t\n] //匹配全部的白字符

一样的,这些也只表示一个字符,这是一个很是重要的。若是要匹配一个由一个小写字母和一位数字组成的字符串,好比"z2"、"t6"或"g7",但不是"ab2"、"r2d3" 或"b52"的话,用这个模式:

^[a-z][0-9]$//尽管[a-z]表明26个字母的范围,但在这里它只能与第一个字符是小写字母的字符串匹配。

前面曾经提到^表示字符串的开头,但它还有另一个含义。当在一组方括号里使用^是,它表示“非”或“排除”的意思,经常用来剔除某个字符。还用前面的例子,咱们要求第一个字符不能是数字:

^[^0-9][0-9]$

这个模式与"&5"、"g7"及"-2"是匹配的,但与"12"、"66"是不匹配的。下面是几个排除特定字符的例子:

[^a-z] //除了小写字母之外的全部字符 
[^\\\/\^] //除了(\)(/)(^)以外的全部字符 
[^\"\'] //除了双引号(")和单引号(')以外的全部字符

特殊字符"." (点,句号)在正规表达式中用来表示除了“新行”以外的全部字符。因此模式"^.5$"与任何两个字符的、以数字5结尾和以其余非“新行”字符开头的字符串匹配。模式"."能够匹配任何字符串,除了空串和只包括一个“新行”的字符串。

PHP的正规表达式有一些内置的通用字符簇,列表以下:

字符簇 含义
[[:alpha:]] 任何字母 
[[:digit:]] 任何数字
[[:alnum:]] 任何字母和数字
[[:space:]] 任何白字符 
[[:upper:]] 任何大写字母
[[:lower:]] 任何小写字母 
[[:punct:]] 任何标点符号
[[:xdigit:]] 任何16进制的数字,至关于[0-9a-fA-F]

 

 

 

 

 

 

 

 

肯定重复出现

到如今为止,你已经知道如何去匹配一个字母或数字,但更多的状况下,可能要匹配一个单词或一组数字。一个单词有若干个字母组成,一组数字有若干个单数组成。跟在字符或字符簇后面的花括号({})用来肯定前面的内容的重复出现的次数。

//字符簇及其含义 
^[a-zA-Z_]$ //全部的字母和下划线 ^[[:alpha:]]{3}$ //全部的3个字母的单词 ^a$ //字母a ^a{4}$ //aaaa ^a{2,4}$ //aa,aaa或aaaa ^a{1,3}$ //a,aa或aaa ^a{2,}$ //包含多于两个a的字符串 ^a{2,} //如:aardvark和aaab,但apple不行 a{2,} //如:baad和aaa,但Nantucket不行 \t{2} //两个制表符 .{2} //全部的两个字符

这些例子描述了花括号的三种不一样的用法。一个数字,{x}的意思是“前面的字符或字符簇只出现x次”;一个数字加逗号,{x,}的意思是“前面的内容出现x或更多的次数”;两个用逗号分隔的数字,{x,y}表示“前面的内容至少出现x次,但不超过y次”。咱们能够把模式扩展到更多的单词或数字:

^[a-zA-Z0-9_]{1,}$ //全部包含一个以上的字母、数字或下划线的字符串 
^[0-9]{1,}$ //全部的正数 
^\-{0,1}[0-9]{1,}$ //全部的整数 
^\-{0,1}[0-9]{0,}\.{0,1}[0-9]{0,}$ //全部的小数

最后一个例子不太好理解,是吗?这么看吧:与全部以一个可选的负号(\-{0,1})开头(^)、跟着0个或更多的数字([0-9]{0,})、和一个可选的小数点(\.{0,1})再跟上0个或多个数字([0-9]{0,}),而且没有其余任何东西($)。下面你将知道可以使用的更为简单的方法。

特殊字符"?"与{0,1}是相等的,它们都表明着:“0个或1个前面的内容”或“前面的内容是可选的”。因此刚才的例子能够简化为:

^\-?[0-9]{0,}\.?[0-9]{0,}$

特殊字符"*"与{0,}是相等的,它们都表明着“0个或多个前面的内容”。最后,字符"+"与 {1,}是相等的,表示“1个或多个前面的内容”,因此上面的4个例子能够写成:

^[a-zA-Z0-9_]+$ //全部包含一个以上的字母、数字或下划线的字符串 
^[0-9]+$ //全部的正数 
^\-?[0-9]+$ //全部的整数 
^\-?[0-9]*\.?[0-9]*$ //全部的小数

固然这并不能从技术上下降正规表达式的复杂性,但可使它们更容易阅读。

 

匹配模式

贪婪模式 

最后须要特别指出的是,正则匹配默认是贪婪匹配,也就是匹配尽量多的字符。举例以下,匹配出数字后面的0

re.match(r'^(\d+)(0*)$', '102300').groups()
('102300', '')

因为\d+采用贪婪匹配,直接把后面的0所有匹配了,结果0*只能匹配空字符串了。

必须让\d+采用非贪婪匹配(也就是尽量少匹配),才能把后面的0匹配出来,加个?就可让\d+采用非贪婪匹配:

re.match(r'^(\d+?)(0*)$', '102300').groups()
('1023', '00')

三种匹配模式

量 词 种 类 意  义
贪婪 勉强 侵占
X? X?? X?+ 匹配 X 零次或一次
X* X*? X*+ 匹配 X 零次或屡次
X+ X+? X++ 匹配 X 一次或屡次
X{n} X{n}? X{n}+ 匹配 X n 次(这个应该不存在这几种模式,就是固定匹配n个)
X{n,} X{n,}? X{n,}+ 匹配 X 至少 n 次
X{n,m} X{n,m}? X{n,m}+ 匹配 X 至少 n 次,但很少于 m 次

 

 

 

 

 

 

想了解更多更详细关于正则匹配模式,能够参考文章:贪婪模式与非贪婪模式详解

 

应用实例

判断功能

//*拿到号码
//*编写规则
//*判断是否符合规则
String phone="13831202155";
//判断功能  电话号码是否正确
String regex="1[3587][0-9]{9}";
boolean isTrueNumber=phone.matches(regex);

分隔功能

//*给定一个字符串
//*编写要分隔的规则(按某种规则分隔)
//*分隔字符串供本身使用
public static void main(String[] args){
String str="我是一个小虫子,一个小星星\\鲁冰花啊";
//定义分隔规则
String regex=",|\\\\";
String[] strs=str.split(regex);
  for (String string : strs) {
    System.out.println(string);
  }
      
}

替换功能

//*定义一个要替换的字符串
//*定义替换规则
//*执行
public static void main(String[] args){
        //把这个字符串里的非字母替换成字母j
        String s="jjkds28989309903290nms&……%##mkdskj909293。8 878&……!@~767jhdjku3928832oijdu3928";
        String regex="[^a-zA-Z]";//若是不是字母,则所有替换成字母j
        String result=s.replaceAll(regex, "j");
        System.out.println(result);
}

获取功能

public static void main(String[] args){
        String word="hello my darling,my ha a uiio jh jkjkj hy ew df cv jkkjds hgd";
        //定义规则  \b为单词边界
        String regex="\\b\\w{2}\\b";
        Pattern p=Pattern.compile(regex);
        Matcher m=p.matcher(word);
        while (m.find()) {
            System.out.println("符合规则的单词:"+m.group());
    }
}

判断功能在java中举例

public static void main(String[] args){
        //使用Pattern和matchers类
        //把这个字符串里的非字母替换成字母j
        String s="11111";
        //把正则表达式编译成模式对象
        Pattern p=Pattern.compile("[0-9]+");
        //经过模式对象获得匹配器对象
        Matcher m=p.matcher(s);
        //调用匹配器对象的功能
        boolean isMatch=m.matches();//是否匹配
        if (isMatch) {
            System.out.println("符合规则");
        }else{
            System.out.println("不符合规则");
    }
}

 

正则表达式颇有用,不只在程序中,就是搜索资料也可编写规则提升匹配度啊。理解正则表达式做用含义,学会经常使用正则表达式应用实例,是颇有必要的啊!

正则表达式在线速查手册:速查手册

 

参考资料:

http://www.php100.com/manual/unze.html

廖雪峰老师blog

相关文章
相关标签/搜索