正则表达式

2015年08月31日

什么是正则表达式(Regular Expression)

正则表达式通常用来检索和替换那些符合某个模式(逻辑公式)的文本(即它是用来进行字符串操作的),通常缩写成regex.

使用正则表达式我们可以:
1.判断给定的字符串是否符合过滤逻辑;
2.从给定的字符串中获取我们想要的部分。

正则表达式的常用符号(百度百科)

正则表达式由一些普通字符元字符组成。普通字符包括大小写的字母和数字,而元字符包含了很多特殊的含义。

图片显示

单个大写字母与小写字母含义相反,小写是,大写非

速记理解

正则的难点在于它有很多等价字符:

?等价于{0,1}
*等价于{0,}
+等价于{1,} \d等价于[0,9] digit
\w等价于[A-Za-z_0-9]

^ 开始
$ 结尾
() 域段
[] 包含
[^] 不包含
{n,m} 匹配长度
. 任何单个字符(. 字符点)
| 或 \ 转义
, 分隔

示例

示例1: 将所有方法foo(a,b,c)的实例改为foo(b,a,c)

//$1、$2、...、$99 与 regexp 中的第 1 到第 99 个子表达式相匹配的文本
var target = "a,b,c";
console.log(target.replace(/([^,]*),([^,]*),([^,]*)/, "$2,$1,$3")); //b,a,c

//注意其他语言的临时区域可能是用\1,\2等方式表示,()需要转义
var target1 = "foo(a,b,c)";
console.log(target1.replace(/foo\(([^,]*),([^,]*),([^,]*)\)/g, "foo($2,$1,$3)")); //foo(b,a,c)

//一个正则表达式中最多可以保存9个这句话从此例来看是不对的
var target2 = "a,b,c,d,e,f,g,h,i,j,k";
console.log(target2.replace(/([^,]*),([^,]*),([^,]*),([^,]*),([^,]*),([^,]*),([^,]*),([^,]*),([^,]*),([^,]*),([^,]*)/, "$11, $10, $9, $8, $7, $6, $5, $4, $3, $2, $1")); //k, j, i, h, g, f, e, d, c, b, a 注意: js中对组的定义并非上述表格中的\\( \\),\\确实是转义字符,([^,]*)表示匹配非逗号的字符并保存到临时区域

示例2: 替换指定内容到行尾

var string = "123 abc f";
console.log(string.replace(/abc.*/, "hello world")); //123 hello world

示例3: 给字符串中的数字加[]

//$& 与 regexp 相匹配的子串
var string1 = "abc123def567gh";
console.log(string1.replace(/\d+/g,"[$&]")); //abc[123]def[567]gh  

示例4:删除某行末尾的特定字符

var string2 = "1212abc 2323abcre 232abc";
console.log(string2.replace(/abc$/g, "")); //1212abc 2323abcre 232

零宽断言

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

(?=exp):零宽度正预测先行断言,它断言自身出现的位置的后面能匹配表达式exp:

var string = "I'm singing while you're dancing";
console.log(string.replace(/\b\w+(?=ing\b)/g, "laugh"));

(?<=exp):零宽度正回顾后发断言(javascript不支持)

//node 直接报错
var string2 = "reading a book";
console.log(string2.replace(/(?<=\bre)\w+\b/, "view")); //SyntaxError: Invalid regular expression: /(?<=\bre)\w+\b/: Invalid group

负向零宽

(?!exp):零宽度负预测先行断言,断言此位置的后面不能匹配表达式exp

//我只能爱老婆,不能爱小三
var string3 = "我爱老婆";
var string4 = "我爱小三";
console.log(string3.search(/我爱(?!小三)/)); //0
console.log(string4.search(/我爱(?!小三)/)); //-1

javascript中的正则

RegExp对象表示正则表达式

直接量语法(字面量是声明方式),注意pattern不能是字符串(即不要用“”)
/pattern/attributes

创建 RegExp 对象的语法:参数attributes可选,包含属性 "g"、"i" 和 "m",分别用于指定全局匹配、区分大小写的匹配和多行匹配
new RegExp(pattern, attributes);

####js的RegExp对象有三个方法(对象方法):
test():检索字符串中的指定值。返回值是true或false
exec():检索字符串中的指定值。返回值是被找到的值。如果没有发现匹配,则返回null。(exec可以说是test的升级版本,因为它不仅可以检测,而且检测到了可以直接提取结果。)

var string = "you love me and I love you";
var pattern = /you/g;
//如果使用 “g” 参数,exec()的工作原理如下:1.找到第一个 “you”,并存储其位置; 2:如果再次运行exec(),则从存储的位置(lastIndex)开始检索,并找到下一个“you”,并存储其位置(我们可以通过反复调用 exec() 方法来遍历字符串中的所有匹配文本。当 exec() 再也找不到匹配的文本时,它将返回 null,并把 lastIndex 属性重置为 0)
console.log(pattern.exec(string)); //[ 'you', index: 0, input: 'you love me and I love you' ]
console.log(pattern.exec(string)); //[ 'you', index: 23, input: 'you love me and I love you' ]
console.log(pattern.exec(string)); //null


//此示例中输出的第0个元素是与正则表达式相匹配的文本,第1个元素是与RegExpObject的第1个子表达式相匹配的文本(如果有的话),第2个元素是与 RegExpObject 的第 2 个子表达式相匹配的文本(如果有的话),以此类推。子表达式就是pattern里()内的东西
var s = 'you love me and I love you';
var pattern = /y(o?)u/;
var ans = pattern.exec(s);
console.log(ans);   // ["you", "o", index: 0, input: "you love me and I love you"]
console.log(ans.length) // 2  index和input只是数组属性 compile():用于改变 RegExp,既可以改变检索模式,也可以添加或删除第二个参数  

####支持正则表达式的String对象的方法:
search:检索与正则表达式相匹配的值(test只能判断有木有,search还能返回位置!当然test()如果有需要能继续找下去,而search则会自动忽略g(如果有的话),与string的indexOf相比,indexOf方法可以从指定位置开始查找,但是不支持正则)

var string = "zhao qian";
//第一个与regexp相匹配的子串的起始位置,没有找到任何匹配的子串,则返回 -1
console.log(string.search(/qian/)); //5
console.log(string.search(/美/)); //-1
//search() 方法不执行全局匹配,它将忽略标志g,总是返回stringObject的第一个匹配的位置
console.log(string.search(/a/)); //2

match:找到一个或多个正则表达式的匹配,很大程度上有赖于regexp是否具有标志g

//此例不含全局属性
var str = "Hello world!";
//找到了一个或多个匹配子串,则返回一个数组
console.log(str.match("world")); //[ 'world', index: 6, input: 'Hello world!' ]
//没有找到任何匹配的子串,则返回 null
console.log(str.match("world").length); //1
console.log(str.match("World")); //null
console.log(str.match("worlld")); //null
console.log(str.match("world!")); //[ 'world!', index: 6, input: 'Hello world!' ]
replace:替换与正则表达式匹配的子串  

//全局匹配返回的数组的内容与前者大不相同,它的数组元素中存放的是 stringObject 中所有的匹配子串,而且也没有 index 属性或 input 属性
var str1 = "1 plus 2 equal 3";
console.log(str1.match(/\d+/g)); //[ '1', '2', '3' ]

replace: 在字符串中用一些字符替换另一些字符,或替换一个与正则表达式匹配的子串。stringObject.replace(regexp/substr,replacement)。replacement可以是一个字符串也可以是一个函数

字符 描述
$1、$2、…、$99 与 regexp 中的第1到第99个子表达式相匹配的文本。
$& 与 regexp 相匹配的子串。
$` 位于匹配子串左侧的文本。
$’ 位于匹配子串右侧的文本。
$$ 直接量符号。
var string3 = "aaa bbb ccc";
console.log(string3.replace(/\b\w+\b/g, function(word) {
	return word.substring(0, 1).toUpperCase() + word.substring(1);
})); //Aaa Bbb Ccc

split:把字符串分割为字符串数组。stringObject.split(separator, howmany)

var str = "How are you doing today?";

console.log(str.split(" ")); //[ 'How', 'are', 'you', 'doing', 'today?' ]
console.log(str.split("")); 
console.log(str.split(" ",3)); //[ 'How', 'are', 'you' ]

项目中见过的一些正则

来自商品详情页 提取下面字符串中的img的src属性

var string = '' + 
'<style>*{margin:0;padding:0}body{background-color:#eee}p img{display:block;width:100%}.detail{background-color:#fff;padding:.6rem .4rem;font-size:.6rem;color:#000}.detail img{display:block;width:auto}.detail img.placeholderfull{width:100%;height:auto!important}.detail img.full{width:100%}.detail img.placeholder{width:1px}.detail img:last-of-type{margin-bottom:.3rem}</style>' + 
'<script>!function(a){function g(){a.rem=e.getBoundingClientRect().width/16,e.style.fontSize=a.rem+"px"}var b,h,c=a.navigator.appVersion.match(/iphone/gi)?a.devicePixelRatio:1,d=1/c,e=document.documentElement,f=document.createElement("meta");a.dpr=c,a.addEventListener("resize",function(){clearTimeout(b),b=setTimeout(g,300)},!1),a.addEventListener("pageshow",function(a){a.persisted&&(clearTimeout(b),b=setTimeout(g,300))},!1),e.setAttribute("data-dpr",c),f.setAttribute("name","viewport"),f.setAttribute("content","initial-scale="+d+", maximum-scale="+d+", minimum-scale="+d+", user-scalable=no"),e.firstElementChild?e.firstElementChild.appendChild(f):(h=document.createElement("div"),h.appendChild(f),document.write(h.innerHTML)),g()}(window);</script>' + 
'<section class="detail">' + 
	'<p>' + 
		'<img src="http://gw.alicdn.com/imgextra/i2/467005089/TB2J9M1cpXXXXcsXpXXXXXXXXXX-467005089.jpg"/>' + 
		'<img src="http://gw.alicdn.com/imgextra/i3/467005089/TB25aA2cpXXXXboXpXXXXXXXXXX-467005089.jpg"/>' + 
		'<img src="http://gw.alicdn.com/imgextra/i4/467005089/TB295s5cpXXXXXxXpXXXXXXXXXX-467005089.jpg"/>' + 
	'</p>' + 
'</section>' + 
'<script>var imgs=document.querySelectorAll(".detail img");for(var i=0;i<imgs.length;i++){imgs[i].addEventListener("load",function(){if(this.getAttribute("src")=="http://s0.husor.cn/image/app/beibei_loading.jpg"){this.className="placeholderfull"}else{this.className="";if(this.width==1){this.className="placeholder"}else{this.className="full"}}})};</script>';

var strStyle = string.replace(/<style>[\s\S]*?<\/style>/gi, "");
console.log("------去掉所有style标签");
console.log(strStyle);

var strScript = strStyle.replace(/<script[\s\S]*?<\/script>/gi, "");
console.log("------去掉所有script标签");
console.log(strScript);

var urls = strScript.match(/src="[\s\S]*?"/gi);
console.log("------提取所有是src属性");
console.log(urls); //[ 'src="http://gw.alicdn.com/imgextra/i2/467005089/TB2J9M1cpXXXXcsXpXXXXXXXXXX-467005089.jpg"','src="http://gw.alicdn.com/imgextra/i3/467005089/TB25aA2cpXXXXboXpXXXXXXXXXX-467005089.jpg"','src="http://gw.alicdn.com/imgextra/i4/467005089/TB295s5cpXXXXXxXpXXXXXXXXXX-467005089.jpg"' ]

上面的示例中需要注意的一点是贪婪模式与非贪婪模式,即[\s\S]*后面加不加?,如果不加这个?

var strScript = strStyle.replace(/<script[\s\S]*?<\/script>/gi, ""); //直接会匹配到最后一个</script>,导致中间的html信息全部没有

来自grunt 给html文件中外部引用文件加时间戳

var string = '<script type="text/javascript" src="/assets/js/detail/app-detail.js"></script>';
console.log(string.replace(/<script([\s\S]*)src="([\s\S]*)"><\/script>/, "<script$1src=\"$2?v=" + new Date().getTime() + "\"></script>")); ### 参考链接 [我所认识的JavaScript正则表达式](http://www.php100.com/html/it/biancheng/2015/0320/8825.html)   [w3school JavaScript RegExp 对象](http://www.w3school.com.cn/jsref/jsref_obj_regexp.asp)