[关闭]
@a5635268 2016-05-05T09:17:46.000000Z 字数 9163 阅读 1221

正则表达式

正则表达式


运算顺序

  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]

元字符

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

. 除换行符以外的任何一个字符
| 或的意思,匹配其中一项就代表匹配成功
  1. /^\d{15}|\d{18}$/ //匹配身份证号,旧版是15位数字,新版是18位数字
  2. /\S+/ //匹配不包含空白符的字符串。
  3. /<a[^>]+>/ //匹配用尖括号括起来的以a开头的字符串。

原子表

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

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

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

原子分组

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

  1. //构造函数方式:
  2. var reg = new RegExp("(hdw)123\\1","i");// \\1,代表把第一个原子组hdw,再次引用一遍;
  3. alert(reg.test("hdw123hdw"));//有反向引用的时候,必须是hdw123hdw才能匹配成功,没反向引用的时候hdw123既可
  4. //字面量方式:
  5. var reg = /(hdw)(haha)123\2/i; //把第二个原子组再次引用一次;
  6. alert(reg.test("hdwhaha123haha")); //true;
  7. //可自定义原子分组名称:
  8. /\b(?<Word>\w+)\b\s+\k<Word>\b/ // /\b(\w+)\b\s+\1\b/ 命名:(?<Word>\w+)(或者把尖括号换成'也行:(?'Word'\w+)) 替换:\k<Word>或者\k'Word'

断言匹配

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

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

零宽断言

  1. /\b\w+(?=ing\b)/ //匹配以ing结尾的单词的前面部分(除了ing以外的部分),如查找I'm singing while you're dancing.时,它会匹配sing和danc
  2. /(?<=\bre)\w+\b/ //会匹配以re开头的单词的后半部分(除了re以外的部分),例如在查找reading a book时,它匹配ading。
  3. /(?<=\s)\d+(?=\s)/ //匹配以空白符间隔的数字(再次强调,不包括这些空白符)。
  1. $str3 = "nixi8.comjyhnixi8.cndsdf";
  2. preg_match("/nixi8(?=\.com)/",$str3,$arr);
  3. /*
  4. 结果
  5. Array
  6. (
  7. [0] => nixi8 -> 断言匹配不包括断言部分;
  8. )
  9. */

负向零宽断言

  1. /\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。
  2. /\d{3}(?!\d)/ //匹配三位数字,而且这三位数字的后面不能是数字;
  3. /\b((?!abc)\w)+\b/ //匹配不包含连续字符串abc的单词。
  4. /(?<![a-z])\d{7}/ //匹配前面不是小写字母的七位数字。
  5. /(?<=<(\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次以上,但尽可能少重复
  1. var reg = /a.*b/;
  2. var reg1 = /a.*?b/;
  3. var str = 'assbaab'; //reg匹配全部,reg1匹配'assb'

限定匹配的边界

^   匹配字符串的开始
$   匹配字符串的结束,忽略换行符
\b  匹配单词的边界
\B  匹配除单词边界以外的边界部分
  1. //构造函数方式:
  2. var reg = new RegExp("(hdw)123\\1","i");// \\1,代表把第一个原子组hdw,再次引用一遍;
  3. alert(reg.test("hdw123hdw"));//有反向引用的时候,必须是hdw123hdw才能匹配成功,没反向引用的时候hdw123既可
  4. //字面量方式:
  5. var reg = /here/i;
  6. alert(reg.test("hereaaa is a word"))//true;
  7. //\b的匹配
  8. var reg = /\bhere\b/i; //加上\b边界符,代表匹配整个单词,可以理解为单词前后需要有空格;
  9. alert(reg.test("hereaaa is a word"))//false;
  10. alert(reg.test("here is a word"))//true;
  11. var reg = /\Bhere\B/i; //加上\B边界符,代表匹配单词前后非字母的;
  12. alert(reg.test("hereaaa is a word"))//false;
  13. alert(reg.test("2here5 is a word"))//true;
  14. var reg = /\bhi\b.*\bLucy\b/i; //先是一个单词hi,然后是任意个任意字符(但不能是换行),最后是Lucy这个单词。
  15. var reg = /\ba\w*\b/ //匹配以字母a开头的单词——先是某个单词开始处(\b),然后是字母a,然后是任意数量的字母或数字(\w*),最后是单词结束处(\b)。
  16. var reg = /\b\w{6}\b/ //匹配刚好6个字符的单词。
  17. /\b(\w+)\b\s+\1\b/ //可以用来匹配重复的单词,像go go, 或者kitty kitty。

模式修正符

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

字符转义

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

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

注释

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

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

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

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

常用正则例子:

  1. /0\d{2}-\d{8}/ //以0开头,然后是两个数字,然后是一个连字号“-”,最后是8个数字.\d后面的{2}({8})的意思是前面\d必须连续重复匹配2次(8次)。
  2. /\(?0\d{2}[) -]?\d{8}/ //首先是一个转义字符\(,它能出现0次或1次(?),然后是一个0,后面跟着2个数字(\d{2}),然后是)或-或空格中的一个,它出现1次或不出现(?),最后是8个数字(\d{8}),但是它也有可能匹配错误的字符串 010)12345678或(022-87654321;所以要用分支条件 |
  3. /0\d{2}-\d{8}|0\d{3}-\d{7}/ //主要匹配两种以连字号分隔的电话号码:一种是以0开头的三位区号,8位本地号(如010-12345678),一种是以0开头的4位区号,7位本地号(0376-2233445)。
  4. /\(?0\d{2}\)?[- ]?\d{8}|0\d{2}[- ]?\d{8}/ //匹配3位区号的电话号码,其中区号可以用小括号括起来,也可以不用,区号与本地号间可以用连字号或空格间隔,也可以没有间隔。
  5. //使用分支条件在匹配时注意匹配的顺序,因为一旦匹配满足就会停止匹配;
  6. /\d{5}-\d{4}|\d{5}/ //美国邮编的规则是5位数字,或者用连字号间隔的9位数字,如果你把它改成\d{5}|\d{5}-\d{4}的话,那么就只会匹配5位的邮编(以及9位邮编的前5位)。
  7. //限定原子组,匹配多个字符;
  8. /(\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地址;
  9. /((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("正则表达式”,"模式修正符")

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

2.通过字面量方式创建

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

配对方法

1.test方法

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

2.exec方法

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

数组包含的属性:

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

  1. var str = "Visit W3School, W3School is a place to study web technology.";
  2. var patt = new RegExp("W3School","g"); //有设置g,代表全局索引,可以用循环来重复匹配;如果没有g,那只能配对一个;
  3. var result;
  4. //result = patt.exec(str);
  5. //console.log('result',result); //result ["W3School", index: 6, input: "Visit W3School, W3School is a place to study web technology."]
  6. while ((result = patt.exec(str)) != null) {
  7. document.write(result);
  8. document.write("<br />");
  9. document.write(patt.lastIndex);
  10. document.write("<br />");
  11. }
  12. /*
  13. ↑↑反复从str匹配patt:
  14. W3School
  15. 14
  16. W3School
  17. 24
  18. */

字符串处理

str.search(regexp)

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

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

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

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

  1. var str = "www.houdunwang.com";
  2. var preg = /w{3}/;
  3. alert(str.replace(preg,'bbs')); //把www.houdunwang.com替换成bbs.houdunwang.com;
  4. var str = "you haha,i haha";
  5. var preg = /haha/g; //加上全局g以后,可反复匹配,不加上g就只能匹配一个,匹配到就停止匹配;
  6. alert(str.replace(preg,'wuwu'));

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

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

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

php部分:

一,创建

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

二,配对方法

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

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

  1. $preg = "/haha/";
  2. $str = "you haha,my haha";
  3. $r = preg_match($preg,$str); //成功返回1,失败返回0
  4. preg_match("/(zh.*u)\s*(g.*g)/", "zhou ganggang", $matches);
  5. print_r($matches);//Array ( [0] => zhou ganggang [1] => zhou [2] => ganggang ),0是与整个模式匹配的结果,1是第一个括号,2是第二括号.....
  6. $url1 = "http://www.126.com";
  7. $url2 = "http://www.sina.com.cn";
  8. $preg = "/http:\/\/www\.\w+\.(com\.cn|com)/i";
  9. preg_match($preg,$url2,$arr);//把$url2与正则匹配的结果返回给$arr;
  10. print_r($arr);//Array ( [0] => http://www.sina.com.cn [1] => com.cn )

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

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

三,字符串处理

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

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

  1. $str = "网站www.nixi8.com论坛bbs.nixi8.com网名NIXI8";
  2. $preg = "/(nixi8)/i";
  3. $new_str = preg_replace($preg,"<span style='color:red'>\\1</span>",$str);//把上面的nixi8描红,本函数与js略有不同,不用加g就是全局匹配;并且\\1必须是两斜杠;
  4. $str = "后盾官网http://www.houdunwang.com后盾论坛https://bbs.houdunwang.com";
  5. $preg = "/(?<!http:\/\/)(?:bbs|www)\.(houdunwang)\.com/isU";
  6. $new_str = preg_replace($preg,'\\1.com',$str);//匹配所有不以http//开始的,bbs或者www.houdunwang.com -忽略大写写i,忽略空白s,匹配到最近的字符串U;然后替换成houdunwang.com
  7. echo $new_str;
  8. #为没有http://的网址加上http:// ↓↓
  9. $str='网站:http://www.nixi8.com;论坛:bbs.zxg.com;商城shop.zxg.cn;域名vip.zxg.com';
  10. $preg='/(?<!http:\/\/)(?:www|bbs|shop|vip)\.?\w+\.(?:com\.cn|com|cn)/i';
  11. $result = preg_replace($preg,"http://\\0",$str);

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

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

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

  1. $text = "April fools day is 04/01/2002\n";
  2. $text.= "Last christmas was 12/24/2001\n";
  3. function next_year($matches) {
  4. // 通常:$matches[0] 是完整的匹配项
  5. // $matches[1] 是第一个括号中的子模式的匹配项
  6. // 以此类推
  7. return $matches[1].($matches[2]+1);
  8. }
  9. echo preg_replace_callback(
  10. "|(\d{2}/\d{2}/)(\d{4})|",
  11. "next_year",
  12. $text); //April fools day is 04/01/2003 Last christmas was 12/24/2002
添加新批注
在作者公开此批注前,只有你和作者可见。
回复批注