什么是正则表达式?
正则表达式(英语:Regular Expression,在代码中常简写为regex、regexp或RE)使用单个字符串来描述、匹配一系列符合某个句法规则的字符串搜索模式。
搜索模式可用于文本搜索和文本替换。
正则表达式是由一个字符序列形成的搜索模式。
当你在文本中搜索数据时,你可以用搜索模式来描述你要查询的内容。
正则表达式可以是一个简单的字符,或一个更复杂的模式。
正则表达式可用于所有文本搜索和文本替换的操作。
语法:/正则表达式主体/修饰符(可选)
修饰符是可选的。
正则表达式修饰符
修饰符可以在全局搜索中不区分大小写。
修饰符 | 描述 |
---|---|
i | 执行对大小写不敏感的匹配。 |
g | 执行全局匹配(查找所有匹配而非在找到第一个匹配后停止)。 |
m | 执行多行匹配。(比如在在\n后会用到) |
元字符
元字符是表达式语法的一部分,在正则表达式中用到的所有元字符有:{ [ ( \ ^ $ | ) ] } ? * + -
如匹配一个问号:var reQMark = /?/; 或 var reQMark = new RegExp("\?"); //注意这里是两个反斜杠,双重转义。
\xxx 查找以八进制数 xxx 规定的字符,如:/\142/为字符b
\xdd 查找以十六进制数 dd 规定的字符,如:/\x62/为字符b
\uxxxx 查找以十六进制数 xxxx 规定的 Unicode 字符,如:/\u0062/为字符b
\r 找回车符
\n 查找换行符
\f 查找换页符
\t 查找制表符
\v 查找垂直制表符
\a 查找alert字符
\e 查找escape字符
\cX 查找与X相对应的控制字符
\0 查找 NULL 字符
. 查找单个字符,除了换行和行结束符,等同于[^\n\r]
\w 查找单词字符,等同于[a-zA-Z_0-9]
\W 查找非单词字符,等同于[^a-zA-Z_0-9]
\d 查找数字,等同于[0-9]
\D 查找非数字字符,等同于[^0-9]
\s 查找空白字符,等同于[ \t\n\x0B\f\r],\x0B为垂直tab和\t一样
\S 查找非空白字符,等同于[^ \t\n\x0B\f\r]
方括号
[abc] 查找方括号之间的任何字符
[^abc] 查找任何不在方括号之间的字符
[0-9] 查找任何从 0 至 9 的数字
[a-z] 查找任何从小写 a 到小写 z 的字符
[A-Z] 查找任何从大写 A 到大写 Z 的字符
[A-z] 查找任何从大写 A 到小写 z 的字符
[adgk] 查找给定集合内的任何字符
[^adgk] 查找给定集合外的任何字符
量词
? 匹配任何包含零个或一个的字符串,如:ba?d匹配bd、bad
+ 匹配任何包含至少一个的字符串,如:ba+d匹配bad、baad
* 匹配任何包含零个或多个的字符串,如:ba*d匹配bd、bad、baad
{n} 匹配包含恰好出现n次的序列的字符串,如:ba{1}d匹配bad
{n,m} 匹配包含至少n次但不超过m次 的序列的字符串,如:ba{0,1}d匹配bd、bad
{n,} 匹配包含至少出现n次的序列的字符串,如:ba{0,}匹配bd、bad、baad、baaad
贪婪量词:
先看整个的字符串是否匹配,如果发现没有匹配,去年该字符串中的最后一个字符并再次尝试,如:?、+、*、{n}、{n, m}、{n, },默认就为贪婪量词。
惰性量词:
先看字符串中的第一个字母是否匹配,如果单独这一个字符还不够,就读入下一个字符,组成两个字符的字符串,与贪婪量词的工作方式恰好相反,如:??、+?、*?、{n}?、{n, m}?、{n, }?
支配量词:
只尝试匹配整个字符串,如果整个字符串不能产生匹配,不做进一步尝试,如:?+、++、*+、{n}+、{n, m}+、{n, }+
var sToMatch = "abbbaabbbaaabbb1234";
var re1 = /.*bbb/g; //匹配结果为"abbbaabbbaaabbb"
var re2 = /.*?bbb/g; //只有惰性量词才能匹配成功,匹配结果为"abbb","aabbb","aaabbb"
var re3 = /.*+bbb/g; //匹配不了,直接报错
复杂模式之分组
通过一系列括号包围一系列字符、字符类以及量词来使用的 。
/(dog){2}/ 匹配"dogdog"
/([bd]ad?)*/ 匹配空, “ba”, “da”, “bad”, “dad”
/(mom( and dad)?)/ 匹配"mom", “mom and dad”
/^\s*(.*?)\s+$/ 匹配首尾的空白字符,也可以用/^\s+|\s+$/g
复杂模式之反向引用
也叫捕获性分组,按照从左到右遇到的左括号字符的顺序进行创建和编号的。
例如表达式(A?(B?(C?)))将产生编号从1-3的三个反向引用:(A?(B?(C?)))、(B?(C?))、(C?)
反向引用有几种不同的使用方法:
首先,使用正则表达式对象的test()、match()或search()方法后,反向引用的值可以从RegExp构造函数中获得,如:
var sToMatch = "#123456789";
var reNumbers = /#(\d+)/;
reNumbers.test(sToMatch);
alert(RegExp.$1); //"123456789",$1保存了第一个反向引用,依次可以用$2,$3...
然后,可以直接在定义分组的表达式中包含反向引用,通过使用特殊转义序列如\1、\2等实现
var sToMatch = "dogdog";
var reDogdog = /(dog)\1/; //等同于/dogdog/
alert(reDogdog.test(sToMatch)); //true
第三,反向引用可以用在String对象的replace()方法中,通过使用特殊字符序列如$1、$2等实现
var sToChange = "1234 5678";
var reMatch = /(\d{4}) (\d{4})/;
alert(sToChange.replace(reMatch, "$2 $1")); //"5678 1234"
复杂模式之候选
使用管道符(|)放在两个单独的模式之间
var reBadWords = /badword | anotherbadword/gi;
var sUserInput = "This is a String using badword1 and badword2.";
var sFinalText = sUserInput.replace(reBadWords, function(sMatch){
return sMatch.replace(/./g, "*"); //用星号替换敏感词中的每一个字母
});
复杂模式之非捕获性分组
相比捕获性分组,不会创建反向引用,在较长的正则表达式中,存储反向引用会降低匹配速度,通过使用非捕获性分组,仍然可以拥有与匹配字符串序列同样的能力,而无需存储结果的开销 。
var sToMatch = "#123456789";
var reNumbers = /#(?:\d+)/; //只需要在左括号的后面加上一个问号和一个紧跟的冒号就可创建一个非捕获性分组
reNumbers.test(sToMatch);
alert(RegExp.$1); //"",输出空字符串是因为该分组是非捕获性的
alert(sToMatch.replace(reNumbers, "abcd$1")); //输出结果是"abcd$1"而不是"abcd123456789",不能使用任何反向引用
又比如:
String.prototype.stripHTML = function(){
var reTag = /<(?:.|\s)*?>/g; //匹配所有的HTML标签,防止插入恶意HTML代码
return this.replace(reTag, "");
}
复杂模式之前瞻
告诉正则表达式运算器向前看一些字符而不移动其位置,存在正向前瞻(检查接下来出现的是不是某个特定字符集)和负向前瞻(检查接下来的不应该出现的特定字符集) 。
正向前瞻(?=n) 匹配任何其后紧接指定字符串 n 的但不包括 n的字符串,注意这里的括号不是分组 。
负向前瞻(?!n) 匹配任何其后没有紧接指定字符串 n 的字符串,如:
var sToMatch1 = "bedroom";
var sToMatch2 = "bedding";
var reBed1 = /(bed(?=room))/;
var reBed2 = /(bed(?!room))/;
alert(reBed1.test(sToMatch1)); //true
alert(RegExt.$1); //输出"bed"而不是"bedroom"
alert(reBed1.test(sToMatch2)); //false
alert(reBed2.test(sToMatch1)); //false
alert(reBed2.test(sToMatch2)); //true
alert(RegExt.$1); //输出的也是"bed"
复杂模式之边界
用于正则表达式中表示模式的位置。
n$ 匹配任何结尾为 n 的字符串,如:/(\w+).$/匹配行尾单词"one.","two."等
^n 匹配任何开头为 n 的字符串,如:/^(.+?)\b/匹配起始位置后的一个或多个单词字符
\b 查找位于单词的开头或结尾的匹配,如:/\b(\S+?)\b/g 或 /(\w+)/g匹配从字符串中抽取单词
\B 查找不处在单词的开头或结尾的匹配
复杂模式之多行模式:
var sToMatch = "First second\nthird fourth\nfifth sixth";
var reLastWordOnLine = /(\w+)$/gm;
alert(sToMatch.match(reLastWordOnLine)); //输出["second", "fourth", "sixth"]而不只是"sixth"
RegExp 对象
正则表达式是描述字符模式的对象。
正则表达式用于对字符串模式匹配及检索替换,是对字符串执行模式匹配的强大工具。
语法:
var patt=new RegExp(pattern,modifiers);
或者更简单的方式:
var patt=/pattern/modifiers;
pattern(模式) 描述了表达式的模式。
modifiers(修饰符) 用于指定全局匹配、区分大小写的匹配和多行匹配。
注意:当使用构造函数创造正则对象时,需要常规的字符转义规则(在前面加反斜杠 \)。比如,以下是等价的:
var re = new RegExp("\w+");
var re = /\w+/;
RegExp对象方法
exec:
定义用法:
exec() 方法用于检索字符串中的正则表达式的匹配。
如果字符串中有匹配的值返回该匹配值,否则返回 null。
语法:RegExpObject.exec(string)
test:
定义用法:
test() 方法用于检测一个字符串是否匹配某个模式.
如果字符串中有匹配的值返回 true ,否则返回 false。
语法:RegExpObject.test(string)
toString:
定义用法:
toString() 方法返回正则表达式的字符串值。
语法:RegExpObject.toString()
支持正则表达式的String对象的方法
search:
定义用法:
search() 方法用于检索字符串中指定的子字符串,或检索与正则表达式相匹配的子字符串。
如果没有找到任何匹配的子串,则返回 -1。
语法:string.search(searchvalue)
var str="Visit Runoob!";
var n=str.search("Runoob");
输出:6
match:
定义用法:
match() 方法可在字符串内检索指定的值,或找到一个或多个正则表达式的匹配。
注意:
match() 方法将检索字符串 String Object,以找到一个或多个与 regexp 匹配的文本。这个方法的行为在很大程度上有赖于 regexp 是否具有标志 g。如果 regexp 没有标志 g,那么 match() 方法就只能在 stringObject 中执行一次匹配。如果没有找到任何匹配的文本, match() 将返回 null。否则,它将返回一个数组,其中存放了与它找到的匹配文本有关的信息。
语法:string.match(regexp)
var str="The rain in SPAIN stays mainly in the plain";
var n=str.match(/ain/g);
输出:ain,ain,ain
replace:
定义用法:
replace() 方法用于在字符串中用一些字符替换另一些字符,或替换一个与正则表达式匹配的子串。
该方法不会改变原始字符串。
语法:string.replace(searchvalue,newvalue)
var str="Visit Microsoft! Visit Microsoft!";
var n=str.replace("Microsoft","Runoob");
输出:Visit Runoob!Visit Microsoft!
split:
定义用法:
split() 方法用于把一个字符串分割成字符串数组。
提示: 如果把空字符串 ("") 用作 separator,那么 stringObject 中的每个字符之间都会被分割。
注意: split() 方法不改变原始字符串。
语法:string.split(separator,limit)
var str="How are you doing today?";
var n=str.split(" ");
输出:How,are,you,doing,today?
RegExp对象属性
属性 | 描述 |
---|---|
constructor | 返回一个函数,该函数是一个创建 RegExp 对象的原型。 |
global | 判断是否设置了 “g” 修饰符 |
ignoreCase | 判断是否设置了 “i” 修饰符 |
lastIndex | 用于规定下次匹配的起始位置 |
multiline | 判断是否设置了 “m” 修饰符 |
source | 返回正则表达式的匹配模式 |
问号在正则中的五大作用
问号左边是非量词元字符:本身代表量词元字符,出现零到一次
问号左边是量词元字符:取消捕获时候的贪婪性
(?:)只匹配不捕获
(?=)正向预查
(?!)负向预查
正则表达式() [] {}的不同意思
() 是为了提取匹配的字符串。表达式中有几个()就有几个相应的匹配字符串。
(\s*)表示连续空格的字符串。
[]是定义匹配的字符范围。比如 [a-zA-Z0-9] 表示相应位置的字符要匹配英文字符和数字。[\s*]表示空格或者号。
{}一般用来表示匹配的长度,比如 \s{3} 表示匹配三个空格,\s[1,3]表示匹配一到三个空格。
(0-9) 匹配 '0-9′ 本身。 [0-9] 匹配数字(注意后面有 *,可以为空)[0-9]+ 匹配数字(注意后面有 +,不可以为空){1-9} 写法错误。
[0-9]{0,9} 表示长度为 0 到 9 的数字字符串。
()和[]有本质的区别
()内的内容表示的是一个子表达式,()本身不匹配任何东西,也不限制匹配任何东西,只是把括号内的内容作为同一个表达式来处理,例如(ab){1,3},就表示ab一起连续出现最少1次,最多3次。如果没有括号的话,ab{1,3},就表示a,后面紧跟的b出现最少1次,最多3次。另外,括号在匹配模式中也很重要。这个就不延伸了,LZ有兴趣可以自己查查
[]表示匹配的字符在[]中,并且只能出现一次,并且特殊字符写在[]会被当成普通字符来匹配。例如[(a)],会匹配(、a、)、这三个字符。
所以() [] 无论是作用还是表示的含义,都有天壤之别,没什么联系。
常用的正则小练
手机号:
请输入手机号:<input type="text" id="phone">
<button onclick="checkPhone()">检查</button>
<script>
function checkPhone(){
var phone = document.getElementById('phone').value;
if(!(/^1(3|4|5|7|8|9)\d{9}$/.test(phone))){
console.log("手机号码有误,请重填");
return false;
} else if(phone.slice(1,2)=="3"||phone.slice(1,2)=="4"||phone.slice(1,2)=="5"||phone.slice(1,2)=="7"){
console.log("你输入的手机号正确属于移动运营商");
}else if(phone.slice(1,2)=="8"||phone.slice(1,2)=="9"){
console.log("你输入的手机号正确属于联通运营商");
}
else {
console.log("您输入的手机号格式正确3keyou")
}
}
</script><br>
邮箱(个别不是所有):
请输入邮箱:<input type="text" id="email">
<button onclick="checkEmail()"> 检查</button>
<script>
function checkEmail(){
var email=document.getElementById("email").value
console.log(email)
if(!(/^[\d\w]{5,20}@(163|qq|126|sina)\.(com|cn|gov)$/.test(email))){
alert("您输入的邮箱格式错误");
return false;
}else{
alert("你输入的邮箱格式正确")
}
}
</script><br>
敏感词过滤:
输入:<input type="text" id="filter">
<button onclick="wordFilter()">敏感词过滤</button>
<script>
function wordFilter(){
var filter=document.getElementById("filter").value
var n_filter=filter.replace(/[滚|你妈|渣男]/g,"*")
document.getElementById("filter").value=n_filter;
console.log(n_filter);
}
</script><br>
身份证号(18位):
请输入你的身份证号:<input type="text" id="idcard">
<button onclick="checkIDcard()">check</button>
<script>
// 1800-2399 闰年29不能少 最后一位可取X或x
function checkIDcard(){
var idcard=document.getElementById("idcard").value
if(!(/^[1-9]\d{5}(18|19|([23]\d))\d{2}((0[1-9])|(10|11|12))(([0-2][1-9])|10|20|30|31)\d{3}[0-9Xx]$/.test(idcard))){
alert("您输入的身份证信息有误")
}
else{
alert("您输入的身份证信息正确")
}
}
</script><br>
IPv4地址:
请输入IPv4的地址:<input type="text" id="ipv4">
<button onclick="checkIP()">check</button>
<script>
function checkIP(){
var ipv4=document.getElementById("ipv4").value;
if(!(/^((\d|[1-9]\d|1\d{2}|2[0-4]\d|25[0-5])\.){3}(\d|[1-9]\d|1\d{2}|2[0-4]\d|25[0-5])$/.test(ipv4))){
alert("您的IPv4地址输入有误")
}else{
alert("您的IPv4地址输入正确")
}
}
</script>