本文前半部分转自:正则表达式–零宽断言详解
零宽断言的意思是(匹配宽度为零,满足一定的条件/断言) 我也不知道这个词语是那个王八蛋发明的,简直是太拗口了。
零宽断言用于查找在某些内容(但并不包括这些内容)之前或之后的东西,也就是说它们像\b,^,$那样用于指定一个位置,这个位置应该满足一定的条件(即断言),因此它们也被称为零宽断言。
断言用来声明一个应该为真的事实。正则表达式中只有当断言为真时才会继续进行匹配。
其中零宽断言又分四种
先行断言:也叫零宽度正预测先行断言(?=表达式),表示匹配表达式前面的位置
例如 [a-z]*(?=ing) 可以匹配cooking singing 中的cook与sing
注意:先行断言的执行步骤是这样的先从要匹配的字符串中的最右端找到第一个ing(也就是先行断言中的表达式)然后 再匹配其前面的表达式,若无法匹配则继续查找第二个ing 再匹配第二个 ing前面的字符串,若能匹配则匹配
例如:.*(?=ing) 可以匹配cooking singing 中的cooking sing 而不是 cook
后发断言:也叫零宽度正回顾后发断言(?<=表达式) ,表示匹配表达式后面的位置
例如(?<=abc).* 可以匹配abcdefg中的defg
注意:后发断言跟先行断言恰恰相反 它的执行步骤是这样的:先从要匹配的字符串中的最左端找到第一个abc(也就是先行断言中的表达式)然后 再匹配其后面的表达式,若无法匹配则继续查找第二个abc 再匹配第二个abc后面的字符串,若能匹配则匹配
例如(?<=abc).* 可以匹配abcdefgabc中的defgabc 而不是abcdefg
负向零宽断言
负向零宽断言 (?!表达式) 也是匹配一个零宽度的位置,不过这个位置的“断言”取表达式的反值,例如 (?!表达式) 表示 表达式 前面的位置,如果 表达式 不成立 ,匹配这个位置;如果 表达式 成立,则不匹配:同样,负向零宽断言也有“先行”和“后发”两种,负向零宽后发断言为 (?<!表达式)
负向零宽后发断言(?<!表达式)
负向零宽先行断言 (?!表达式)
负向零宽断言要注意的跟正向的一样
注:以上内容转自 正则表达式–零宽断言详解
零宽断言小结:
零宽断言 | (?=exp) | 匹配exp前面的位置 |
---|---|---|
(?<=exp) | 匹配exp后面的位置 | |
(?!exp) | 匹配后面跟的不是exp的位置 | |
(?<!exp) | 匹配前面不是exp的位置 |
一个应用
前面有篇博客中写过一个面试题,就是把一个数字每三位加一个逗号,之前写的代码是这样的:
function numFormat(val){ var numStr = val.toString(), length = numStr.length, extra = length % 3, count = (length - extra)/3, result = numStr.substr(0,extra); for(var i = 0; i < count; i++){ result += "," + numStr.substr(extra+i * 3,3); } return result.replace(/^,/,""); } //Test console.log(numFormat(12));//12 console.log(numFormat(123));//123 console.log(numFormat(1234));//1,234 console.log(numFormat(123456789));//123,456,789
这里用的方法是解析字符串得到的,并且没有考虑小数的情况,后来在百度的Tangarm类库中看到也有这个方法,不过是用正则实现的,很巧妙,于是我把代码改为下面的:
function numberFormat(val){ var numArr=String(val).split("."); numArr[0] = numArr[0].replace(/(\d)(?=(\d{3})+$)/ig,"$1,"); return numArr.join("."); } //Test console.log(numberFormat(123456));//123,456 console.log(numberFormat(12345678));//12,345,678
大家看看代码是不是简洁了好多,如果不考虑小数部分一行代码就可以了。
这里主要就是利用了先行断言,把连续三个数字的前一个数字换为数字加一个逗号。