正则表达式小结

运算顺序

  1. ( ) 圆括号因为是内存处理所以最高
  2. * ? + { } 重复匹配内容其次
  3. ^ $ \b 边界处理第三
  4. | 条件处理第四 最后按照从左到右来匹配

原子

原子是正则表达式中的最小的元素,包括英文、标点符号等。代表只匹配一个

\d  匹配任意一个数字 [0-9]
\D 与除了数字以外的任何一个字符匹配 [^0-9]
\w 与任意一个英文字母,数字或下划线匹配 [a-z0-9A-Z_]
\W 除了字母,数字或下划线外与任何一个字符匹配 [â-z0-9A-Z_]
\s 与任意一个空白字符匹配 [\n\f\r\t\v]
\f 换页字符;
\n 换行字符;
\r 回车字符;
\t 制表符;
\v 垂直制表符;
\S 与除了空白符外任意一个字符匹配 [^\n\f\r\t\v]

元字符

代表着特殊意义的特殊字符

. 除换行符以外的任何一个字符
| 或的意思,匹配其中一项就代表匹配成功
/^\d{15}|\d{18}$/ //匹配身份证号,旧版是15位数字,新版是18位数字

/\S+/ //匹配不包含空白符的字符串。

/<a[^>]+>/  //匹配用尖括号括起来的以a开头的字符串。

原子表

相当于或的一个集合,只匹配到原子表中的任一个就代表成功.

[]       只匹配其中的一个原子
[0-9]    匹配0-9任何一个数字
[a-z]    匹配小写a-z任何一个字母
[A-Z]    匹配大写A-Z任何一个字母
[^]     只匹配"除了"其中字符的任意一个原子
/[^x]/         //匹配除了x以外的任意字符

/[^aeiou]/	 //匹配除了aeiou这几个字母以外的任意字符

上面都是只匹配一个字符,如果要匹配多个字符,用原子分组;

原子分组

分组代表一个原子集合或者说一个大原子(每个括号必须要全部按顺序),并压入堆栈(内存)用于调用,组号是从左到右计数的调用时:在js中如果是字面量形式用\1,构造函数方式用\1 这种方式我们叫做反向引用,如果不想让其到内存中可以用(?:exp)来匹配;另外,在php中\0代表匹配到的全部内容;\1,\2..同上

//构造函数方式:
var reg = new RegExp("(hdw)123\\1","i");// \\1,代表把第一个原子组hdw,再次引用一遍;
alert(reg.test("hdw123hdw"));//有反向引用的时候,必须是hdw123hdw才能匹配成功,没反向引用的时候hdw123既可

//字面量方式:
var reg = /(hdw)(haha)123\2/i;  //把第二个原子组再次引用一次;
alert(reg.test("hdwhaha123haha")); //true;

//可自定义原子分组名称:
/\b(?<Word>\w+)\b\s+\k<Word>\b/ // /\b(\w+)\b\s+\1\b/  命名:(?<Word>\w+)(或者把尖括号换成'也行:(?'Word'\w+)) 替换:\k<Word>或者\k'Word'

断言匹配

用于查找在某些内容(但并不包括这些内容)之前或之后的东西,也就是说它们像\b,^,$那样用于指定一个位置,这个位置应该满足一定的条件(即断言),因此它们也被称为零宽断言。

断言用来声明一个应该为真的事实。正则表达式中只有当断言为真时才会继续进行匹配。

零宽断言

  • (?=exp) 后面必须是以exp结束的
  • (?<=exp) 前面必须是以exp开始的
/\b\w+(?=ing\b)/ //匹配以ing结尾的单词的前面部分(除了ing以外的部分),如查找I'm singing while you're dancing.时,它会匹配sing和danc

/(?<=\bre)\w+\b/ //会匹配以re开头的单词的后半部分(除了re以外的部分),例如在查找reading a book时,它匹配ading。

/(?<=\s)\d+(?=\s)/ //匹配以空白符间隔的数字(再次强调,不包括这些空白符)。
$str3 = "nixi8.comjyhnixi8.cndsdf";	
preg_match("/nixi8(?=\.com)/",$str3,$arr);

/*
	结果
		Array
	(
		[0] => nixi8 -> 断言匹配不包括断言部分;
	)
*/

负向零宽断言

  • /(?!exp)/ 后面必须不是以exp结束的
  • /(?<!exp)/ 前面必须不是以exp开始的
/\b\w*q[^u]\w*\b/ //匹配包含后面不是字母u的字母q的单词。但是如果q出现在单词的结尾的话,像Iraq,Benq,这个表达式就会出错。这是因为[^u]总要匹配一个字符,所以如果q是单词的最后一个字符的话,后面的[^u]将会匹配q后面的单词分隔符(可能是空格,或者是句号或其它的什么),后面的\w*\b将会匹配下一个单词,于是\b\w*q[^u]\w*\b就能匹配整个Iraq fighting。负向零宽断言能解决这样的问题,因为它只匹配一个位置,并不消费任何字符。现在,我们可以这样来解决这个问题:\b\w*q(?!u)\w*\b。

/\d{3}(?!\d)/ //匹配三位数字,而且这三位数字的后面不能是数字;

/\b((?!abc)\w)+\b/ //匹配不包含连续字符串abc的单词。

/(?<![a-z])\d{7}/ //匹配前面不是小写字母的七位数字。

/(?<=<(\w+)>).*(?=<\/\1>)/ //不包含属性的简单HTML标签内里的内容,(?<=<(\w+)>)指定了这样的前缀:被尖括号括起来的单词(比如可能是<b>),然后是.*(任意的字符串),最后是一个后缀(?=<\/\1>)。注意后缀里的\/,它用到了前面提过的字符转义;\1则是一个反向引用,引用的正是捕获的第一组,前面的(\w+)匹配的内容,这样如果前缀实际上是<b>的话,后缀就是</b>了。整个表达式匹配的是<b>和</b>之间的内容(再次提醒,不包括前缀和后缀本身)

量词

可以使用一些元字符,重复表示一些原子或元字符

*        重复零次或更多次
+        重复一次或更多次
?        重复零次或一次
{n}      重复n次
{n,}     重复n次或更多次
{n,m}    重复n到m次

量词的匹配默认情况下是尽量多的匹配,也即是贪婪匹配,变贪婪匹配为吝啬匹配可以用下面的方式;也就是对有选择匹配多或少的情况下再加一个问号,代表尽量少的匹配;

*?     重复任意次,但尽可能少重复
+?     重复1次或更多次,但尽可能少重复
??     重复0次或1次,但尽可能少重复
{n,m}? 重复n到m次,但尽可能少重复
{n,}?  重复n次以上,但尽可能少重复
var reg = /a.*b/;
var reg1 = /a.*?b/;
var str = 'assbaab'; //reg匹配全部,reg1匹配'assb'

限定匹配的边界

^   匹配字符串的开始
$   匹配字符串的结束,忽略换行符
\b  匹配单词的边界
\B  匹配除单词边界以外的边界部分
//构造函数方式:
var reg = new RegExp("(hdw)123\\1","i");// \\1,代表把第一个原子组hdw,再次引用一遍;
alert(reg.test("hdw123hdw"));//有反向引用的时候,必须是hdw123hdw才能匹配成功,没反向引用的时候hdw123既可

//字面量方式:
var reg = /here/i;  
alert(reg.test("hereaaa is a word"))//true;

//\b的匹配
var reg = /\bhere\b/i;  //加上\b边界符,代表匹配整个单词,可以理解为单词前后需要有空格;
alert(reg.test("hereaaa is a word"))//false;
alert(reg.test("here is a word"))//true;

var reg = /\Bhere\B/i;  //加上\B边界符,代表匹配单词前后非字母的;
alert(reg.test("hereaaa is a word"))//false;
alert(reg.test("2here5 is a word"))//true;

var reg = /\bhi\b.*\bLucy\b/i; //先是一个单词hi,然后是任意个任意字符(但不能是换行),最后是Lucy这个单词。

var reg = /\ba\w*\b/ //匹配以字母a开头的单词——先是某个单词开始处(\b),然后是字母a,然后是任意数量的字母或数字(\w*),最后是单词结束处(\b)。

var reg = /\b\w{6}\b/ //匹配刚好6个字符的单词。

/\b(\w+)\b\s+\1\b/ //可以用来匹配重复的单词,像go go, 或者kitty kitty。

模式修正符

i   不区分大小写字母的匹配
m   将字符串视为多行,匹配的字符串默认是一行,如果加了m的这个修饰符的话,^和$的意义就变成了匹配行的开始处和结束处。
g   全局匹配,找到所有匹配项,注意在php中g的模式是没有的,replace默认就是全部匹配的,preg_match_all为全匹配;
x   模式中的空白忽略不计
U   匹配到最近的字符串
e   将替换的字符串作为表达使用
$auth = '喂喂??嘿嘿??';
$query = preg_replace('/^.+\?/U','',$auth); //?嘿嘿?? 不加U 全部替换掉了;

字符转义

要匹配在正则中已有意义的符号 . * [ ] $ ( ) + ? \ ^ { } |,就必须全部加上 \;

注意↑↑,如果是在原子表或原子分组中, . ? 不用加上\;

注释

另外,小括号的另一种用途是通过语法(?#comment)来包含注释。例如:

2[0-4]\d(?#200-249)|25[0-5](?#250-255)|[01]?\d\d?(?#0-199)。

再匹配的时候启用“忽略模式里的空白符”选项 可以匹配到这种更详细注释的↓↓

/
(?<=    # 断言要匹配的文本的前缀
<(\w+)> # 查找尖括号括起来的字母或数字(即HTML/XML标签)
)       # 前缀结束
.*      # 匹配任意文本
(?=     # 断言要匹配的文本的后缀
<\/\1>  # 查找尖括号括起来的内容:前面是一个"/",后面是先前捕获的标签
)       # 后缀结束
/x

常用正则例子:

/0\d{2}-\d{8}/ //以0开头,然后是两个数字,然后是一个连字号“-”,最后是8个数字.\d后面的{2}({8})的意思是前面\d必须连续重复匹配2次(8次)。

/\(?0\d{2}[) -]?\d{8}/ //首先是一个转义字符\(,它能出现0次或1次(?),然后是一个0,后面跟着2个数字(\d{2}),然后是)或-或空格中的一个,它出现1次或不出现(?),最后是8个数字(\d{8}),但是它也有可能匹配错误的字符串 010)12345678或(022-87654321;所以要用分支条件 |

/0\d{2}-\d{8}|0\d{3}-\d{7}/ //主要匹配两种以连字号分隔的电话号码:一种是以0开头的三位区号,8位本地号(如010-12345678),一种是以0开头的4位区号,7位本地号(0376-2233445)。

/\(?0\d{2}\)?[- ]?\d{8}|0\d{2}[- ]?\d{8}/  //匹配3位区号的电话号码,其中区号可以用小括号括起来,也可以不用,区号与本地号间可以用连字号或空格间隔,也可以没有间隔。

//使用分支条件在匹配时注意匹配的顺序,因为一旦匹配满足就会停止匹配;
/\d{5}-\d{4}|\d{5}/ //美国邮编的规则是5位数字,或者用连字号间隔的9位数字,如果你把它改成\d{5}|\d{5}-\d{4}的话,那么就只会匹配5位的邮编(以及9位邮编的前5位)。

//限定原子组,匹配多个字符;
/(\d{1,3}\.){3}\d{1,3}/ //简单的IP地址匹配,要理解这个表达式,请按下列顺序分析它:\d{1,3}匹配1到3位的数字,(\d{1,3}\.){3}匹配三位数字加上一个英文句号(这个整体也就是这个分组)重复3次,最后再加上一个一到三位的数字(\d{1,3}),不幸的是,它也将匹配256.300.888.999这种不可能存在的IP地址;

/((2[0-4]\d|25[0-5]|[01]?\d\d?)\.){3}(2[0-4]\d|25[0-5]|[01]?\d\d?)/  //01.02.03.04这个其实也是

不同编程语言对应的正则操作

javascript部分:

创建

1.通过构造函数创建 reg=new RegExp("正则表达式”,"模式修正符")

var reg = new RegExp("houdun");
var stat = reg.test("houdunwang"); //返回的是布尔值,成功就为true;
alert(stat);

2.通过字面量方式创建

var reg = /houdun/i; //注意没有双引号
var stat = reg.test("houdunwang");
alert(stat);

配对方法

1.test方法

RegExp.test(str) – 返回一个 Boolean 值,它指出在被查找的字符串中是否存在模式

2.exec方法

RegExp.exec() - 在字符串中匹配正则,成功返回数组,失败返回null

数组包含的属性:

  • input -被匹配的字符串
  • index -子串位置

如果正则表达式没有设置g,那么exec方法不会对正则表达式有任何的影响,如果设置了g,那么exec执行之后会更新正则表达式的lastIndex属性,表示本次匹配后,所匹配字符串的下一个字符的索引,下一次再用这个正则表达式匹配字符串的时候就会从上次的lastIndex属性开始匹配。

var str = "Visit W3School, W3School is a place to study web technology."; 
var patt = new RegExp("W3School","g"); //有设置g,代表全局索引,可以用循环来重复匹配;如果没有g,那只能配对一个;
var result;
//result = patt.exec(str);
//console.log('result',result); //result ["W3School", index: 6, input: "Visit W3School, W3School is a place to study web technology."] 

while ((result = patt.exec(str)) != null)  {
	document.write(result);
	document.write("<br />");
	document.write(patt.lastIndex);
	document.write("<br />");
 }
/*
↑↑反复从str匹配patt:
W3School
14
W3School
24
*/

字符串处理

str.search(regexp)

regexp为正则表达式,反回索引位置,不支持全局索引(即g修饰符无效)找到即停止搜索

var str = "www.houdunwang.com";
alert(str.search(/hou/)); //4,返回找到的位置;

str.replace(正则或字符串,替换的新内容)

支持全局g修饰符,如果模式不是全局,当匹配到一个以后将不会继续匹配,反之则会继续往下匹配。返回替换后的字符串;

var str = "www.houdunwang.com";
var preg = /w{3}/;
alert(str.replace(preg,'bbs')); //把www.houdunwang.com替换成bbs.houdunwang.com;

var str = "you haha,i haha";
var preg = /haha/g; //加上全局g以后,可反复匹配,不加上g就只能匹配一个,匹配到就停止匹配;
alert(str.replace(preg,'wuwu')); 

str.split(字符串或正则,[限定返回的数组元素个数])

拆分字符串,参数可以为字符串或正则表达式

var str = "zhou@xiao&gang#haha";
var preg = /[@&#]/;
var r = str.split(preg);
console.log('str',r);//["zhou", "xiao", "gang", "haha"] 

php部分:

一,创建

"/reg/" '#reg#' '@reg@'  //和js不同,必须要加引号

二,配对方法

int|array preg_match( 正则, 被匹配的字符串 [, array matches ] )

关于第三参数:可选,存储匹配结果的数组,$matches[0] 将包含与整个模式匹配的文本,$matches[1] 将包含与第一个捕获的括号中的子模式所匹配的文本,以此类推

$preg = "/haha/";
$str = "you haha,my haha";
$r = preg_match($preg,$str); //成功返回1,失败返回0
preg_match("/(zh.*u)\s*(g.*g)/", "zhou ganggang", $matches);
print_r($matches);//Array ( [0] => zhou ganggang [1] => zhou [2] => ganggang ),0是与整个模式匹配的结果,1是第一个括号,2是第二括号.....

$url1 = "http://www.126.com";
$url2 = "http://www.sina.com.cn";
$preg = "/http:\/\/www\.\w+\.(com\.cn|com)/i";
preg_match($preg,$url2,$arr);//把$url2与正则匹配的结果返回给$arr;
print_r($arr);//Array ( [0] => http://www.sina.com.cn [1] => com.cn ) 

preg_match_all($preg,$str,$arr) //preg_match满足一次就停止匹配,而preg_match_all会重复匹配;

$str='网站:http://www.hdw.com;论坛:http://bbs.hdw.com;shop.hdw.cn;域名hdw.com';
$preg='/(?<!http:\/\/)(?:\w*)\.?\w+\.(?:com\.cn|com|cn)/is';
preg_match_all($preg,$str,$arr);
/*array的结果
 Array(
  [0] => Array
    (
      [0] => ww.hdw.com  -> www.hdw.com,要从第二个字符开始才满足匹配条件,定义第一个字符就会不出现;
      [1] => bs.hdw.com
      [2] => shop.hdw.cn
      [3] => hdw.com
    )
  )
*/

三,字符串处理

  1. preg_split($preg,$str); 用$preg分割$str,返回分割结果的数组;
$str ="1.jpg@2.jpg@3.jpg#4.jpg";
$preg="/[@#]/";
$arr = preg_split($preg,$str);
print_r($arr);//返回其数组;

2. preg_replace(正则,要替换的,被替换的);返回替换后的字符串;

$str = "网站www.nixi8.com论坛bbs.nixi8.com网名NIXI8";
$preg = "/(nixi8)/i";
$new_str = preg_replace($preg,"<span style='color:red'>\\1</span>",$str);//把上面的nixi8描红,本函数与js略有不同,不用加g就是全局匹配;并且\\1必须是两斜杠;

$str = "后盾官网http://www.houdunwang.com后盾论坛https://bbs.houdunwang.com";
$preg = "/(?<!http:\/\/)(?:bbs|www)\.(houdunwang)\.com/isU";
$new_str = preg_replace($preg,'\\1.com',$str);//匹配所有不以http//开始的,bbs或者www.houdunwang.com -忽略大写写i,忽略空白s,匹配到最近的字符串U;然后替换成houdunwang.com
echo $new_str;

#为没有http://的网址加上http:// ↓↓
$str='网站:http://www.nixi8.com;论坛:bbs.zxg.com;商城shop.zxg.cn;域名vip.zxg.com';
$preg='/(?<!http:\/\/)(?:www|bbs|shop|vip)\.?\w+\.(?:com\.cn|com|cn)/i';  
$result = preg_replace($preg,"http://\\0",$str);

3. array preg_grep ( string $pattern , array $input [, int $flags = 0 ] )

$subjects = array(  
    "Mechanical Engineering", "Medicine",  
    "Social Science", "Agriculture",  
    "Commercial Science", "Politics"  
); 

$alonewords = preg_grep("/^[a-z]*$/i",$subjects);//匹配以字母开头并且以字母结束的字符串,不忽略空格,所以^$在遇到空格的时候就会生效;返回的是一个数组,保持原有的索引;有第三参数0|1,默认为0,如果为1的时候就返回相反的结果,也就是不匹配时的结果; 
print_r($alonewords); 
/*
Array
(
	[1] => Medicine
	[3] => Agriculture
	[5] => Politics
)	
*/

4. mixed preg_replace_callback ( mixed pattern, callback callback, mixed subject [, int limit] ) 可以看做是一个有条件处理的preg_replace函数;

$text = "April fools day is 04/01/2002\n";
$text.= "Last christmas was 12/24/2001\n";
function next_year($matches) {
// 通常:$matches[0] 是完整的匹配项
// $matches[1] 是第一个括号中的子模式的匹配项
// 以此类推
return $matches[1].($matches[2]+1);
}
echo preg_replace_callback(
"|(\d{2}/\d{2}/)(\d{4})|",
"next_year",
$text); //April fools day is 04/01/2003 Last christmas was 12/24/2002
posted @ 2017-03-31 11:47  菜问  阅读(780)  评论(0编辑  收藏  举报