在js中,正規表示式是由一個RegExp物件表示的,RegExp 是正規表示式的縮寫。 RegExp簡單的模式可以是一個單獨的字元。更複雜的模式包括了更多的字符,並可用於解析、格式檢查、替換等等。可以使用一個RegExp()建構函數來建立RegExp對象,也可以使用直接量語法。
1、RegExp簡介。
RegExp即正規表示式(Regular Expression,在程式碼中常簡寫為regex、regexp或RE/re/reg),就是使用單一字串來描述、配對一系列符合某個句法規則的字串搜尋模式,搜尋模式可用於文字搜尋和文字取代。
正規表達式是由一個字元序列形成的搜尋模式,當你在文字中搜尋資料是,你可以用搜尋模式來描述你要查詢的內容,也就是說正規表示式是描述字元模式的對象,可用於對字串模式匹配及檢索替換,是對字串執行模式匹配的強大工具。
所謂正則表達式,直接可理解為規則或者模式表達式,就是表達了某一種計算機可以理解的規則,而一般人很難讀懂的文字表達方式,可用於所有文本搜索和文本替換的操作,簡單說就是處理字串。
2、字串方法。
(1)、charAt() 取得某個字符,傳回字串某一位的字符。
(2)、split() 分割字串,取得陣列。
(3)、search() 找某個字元首次出現的位置,配合正規使用較好,傳回值為數值,沒找到回傳-1。
(4)、match() 查找字串中指定字符並返回該字符,如果不使用正則,則只返回首次出現的指定字符,不會再向後匹配,如果使用正則並進行全局匹配,則以數組形式傳回字串中所有指定的字符,沒找到則傳回null。
(5)、replace() 替換字符,傳回一個新字串,配合正則使用更好,可以替換所有匹配。
<script> var str='abcdefgca'; //返回字符串中某一位的字符。 alert(str.charAt()); //返回:d //查找字符串首次出现的位置。 alert(str.search('z')); //返回:- //查找指定的字符。 //只返回第一次出现的c,不再向后匹配。 alert(str.match('c')); //返回:c //将'a'替换为'i'。 //只替换了第一个位置的a,不再向后匹配。 alert(str.replace('a', 'i')); //返回:ibcdefgca //分割字符串。 var str='--aaa--cd'; var arr=str.split('-'); //返回:,,aaa,,cd alert(arr); </script>
實例:使用普通方法找出字串中所有數字
實現想法:要找出字串中的數字,其實也不難,使用判斷先將字串中的數字提取出來,那麼字串中肯定不止一個數字,所以就需要一個空字串來存儲提取出來的數字字符,然後再將這些數字字符添加到數組中,最後返回,這樣就完成了。來看看程式是怎麼實現的:
<script> var str=' abc d aa c zz -=-=s-'; var arr=[]; var num=''; //首先循环遍历字符串 for(var i=;i<str.length;i++){ //再判断当前字符大于等于并且小于等于,则为数字 if(str.charAt(i)>='' && str.charAt(i)<=''){ //那么就将当前的字符存储在空字符串中 num += str.charAt(i); } else{ //如果字符串中有值。 if(num){ //将值添加到数组中。 arr.push(num); //再清空字符串,避免重复添加。 num=''; } } } //最后在整个字符串结束之后有可能还会有数字,再做一次判断。 if(num){ //如果还有值就添加到数组中。 arr.push(num); //再清空字符串。 num=''; } //返回:OK,现在返回就完成了。 alert(arr); //返回:,,,,,,, </script>
雖然可以使用普通方法完成,結構清晰,但是程式碼相對較長,如果使用正則,那麼一個表達式就完成了這麼多工作,非常方便,下面就來看看怎麼使用正則。
3、使用正規。
正規表示式語法:var re = new RegExp('模式', '修飾符');
模式就是表達式的模式,而修飾符是用來指定全域匹配、不區分大小寫等,完整形態就是正規表示式。
看到正規語法長這模樣,不就是JS中典型的新創建對象的語法麼,對了,就是新創建一個正則對象。我們都知道,要盡量避免使用new關鍵字,使用new無疑就是新創建了一個對象,那麼同時就預示著其佔據了一定的內存空間,如果處理不當,積累多了會造成內存溢出,這樣相當耗費資源,不利於程式碼優化的實作。同時這樣的寫法,體現不出正則的強大,他應該是很簡a潔的才對,因此在實際使用的時候都不採用這種JS風格的正則語法,都使用的是另一種風格,如下:
語法:var re = /模式/修飾符;
這種風格就相對簡潔了,屬於一般人看不懂的表達方式。
(1)、修飾符。
修飾符用於執行全域匹配和區分大小寫。
忽略大小寫:i (ignore的簡寫,中文翻譯為:忽視)
全域匹配:g (global的簡寫,中文翻譯為:全部的/全域的)
實例:全域搜尋指定字元
<script> var str='AbCdEFgiX'; //JS风格: //这个正则表达式什么也不代表,只代表abc本身。 var reg=new RegExp('abc', 'i'); alert(str.match(reg)); //返回:AbC //常用风格: var re=/efg/i; alert(str.match(re)); //返回:EFg </script>
4、方括號和元字元。
(1)、方括號。
方括號用來找出某個範圍內的字元。
①、任意字元
表達式:[abc]
找出方括號中的任意字元。
[]在這裡為或的意思,即隨便出現哪個都行。
<script> var str='apc xpc ppc bpc spc opc'; //[apx]pc,随便出现哪个都行,即:apc ppc xpc var re=/[apx]pc/g; alert(str.match(re)); //返回前个pc。 </script>
②、范围查找。
表达式:[0-9] [a-z] [A-z] [A-Z]
[0-9] 查找任意 0 - 9 的数字。
[a-z] 查找任意 a - z 的字符。
[A-z] 查找任意 大写A - 小写z 的字符。
[A-Z] 查找任意 大写A - 大写Z的字符。
③、排除查找。
表达式:[^abc] [^a-z] [^0-9]
[^abc] 查找任意不在方括号中的字符。
[^a-z] 查找任意除了字母以外的字符,包括数字符号中文外文。
[^0-9] 查找任意除了数字以外的字符,包括字母符号中文外文。
<script> var str='ot out o.t o t o`t ot ot'; //o和t中间除了数字,什么都可以 var re=/o[^-]t/g; alert(str.match(re)); //返回:out,o.t,o t,o`t </script>
④、選擇查找。
表達式:(a|b|c)
找出任何指定的選項,a或b或c。
⑤、配對還可以使用組合模式,例如:[a-z0-9A-Z] [^a-z0-9]
[a-z0-9A-Z] 任意大小寫字母和數字。
[^a-z0-9] 除了字母和數字以外,什麼都可以。
(2)、元字元。
元字符是擁有特殊意義的字符,也可以叫做轉義字符。
以下是一些常用的元字元:
元字元 | 描述 | 使用 |
. | 尋找單一字符,代表任意字符,不包括換行和行結束符。 | 不建議使用,容易出問題。 |
w | 找出單字字符,包括英文數字下劃線,相當於[a-z0-9] | /w/ |
W | 找出非單字字符,相當於[^a-z0-9] | /W/ |
d | 找出數字,相當於[0-9] | /d/ |
D | 找出非數字,相當於[^0-9] | /D/ |
s | 尋找空白字符,包括空格符、回車符、製表符、換行符和換頁符,不可顯示不可列印的字符。 | /s/ |
S | 找出非空白字元。 | /S/ |
b | 尋找位於單字的開頭或結尾的匹配,如果未匹配到,則傳回null。 | /b/ |
B |
找出非單字邊界的匹配,也就是不位於開頭或結尾,匹配位置的上一個和下一個字符的類型是相同的:即必須同為單詞, 或必須同為非單詞,字串的開頭和結尾處被視為非單字字符,如果未匹配到,則傳回null。 |
/B/ |
n | 尋找換行符,如果找到則傳回該位置,如果找不到則傳回-1。 | /n/ |
f | 找換頁符。 | /f/ |
r | 找回車符。 | /r/ |
t | 尋找製表符。 |
5、量詞。
所謂量詞,就是數量詞,即個數,用在正規中,表示出現的次數。
下面是一些常用的量詞:
量詞 | 描述 | 使用 |
* | 零次或任意次,相當於{0,} | 不建議使用,範圍太廣,不夠精確。 |
? | 零次或一次,相當於{0, 1} | /10?/g 對1進行全域搜索,包括其後緊接的零個或1個'0'。 |
一次或任意次,相當於{1, } | /w /g 對至少一個單字進行全域搜尋。 | |
{n} | 剛好n次 | /d{4}/g 對包含四位數的數字進行全域搜尋。 |
{n,} | 至少n次,最多不限 | /d{3,}/g 對包含至少三位數的數字進行全域搜尋。 |
{n, m} | 至少n次,最多m次 | /d{3,4}/g 對包含三位或四位的數字進行全域搜尋。 |
以下是一些常用的配對模式:
模式 | 描述 | 使用 |
^a | 任何開頭為 a 的字符,表示行首 | /^d/ 以數字開頭 /^a/g 全域搜尋以'a'開頭的字元 |
a$ | 任何結尾為 a 的字符,表示行尾 | /d$/ 以數字結尾 /z$/g 全域搜尋以'z'結尾的字元 |
?=a | 任何其後緊接 a 的字符 | /a(?= b)/g 全域搜尋'a'後面跟著'b'的字元 |
?!a | 任何其後沒有緊接 a 的字符 | /c(?= d)/g 全域搜尋'c'後沒有緊接'd'的字元 |
6、字符串和正则配合。
(1)、search()配合正则
实例:找出字符串中第一次出现数字的位置
<script> var str='asdf zxcvbnm'; //元字符d,表示转义为数字 var re=/\d/; alert(str.search(re)); //返回: 第一个数字为出现在第位 </script>
(2)、match()配合正则
其实没有什么东西是非正则不可的,只是正则可以让做东西更方便。下面就完成本章遗留的历史问题,怎么使用正则,能一句代码就完成普通方法需要很多行代码才能完成的东西。
在实例之前,先看看match()与正则的配合。
<script> var str='asdf zxcvm'; //找出字符串中的数字可以使用元字符\d var re=/\d/; //没告诉系统要找多少数字,系统在找到数字后就返回 alert(str.match(re)); //返回: //因此需要全局匹配,使用修饰符g var re=/\d/g; //没告诉系统要找几位,系统会将所有找到的数字返回 alert(str.match(re)); //返回:,,,,,,,,,,,, //所以可以使用两个元字符,告诉系统要找的数字是位 var re=/\d\d/g; //显然这样是不可取的,因为数字的位数并不固定,可能是位,有可能还是多位 alert(str.match(re)); //返回:,,,, //所以需要用到量词+,+代表若干,也就是多少都可以。 var re=/\d+/g; //现在返回正确。 alert(str.match(re)); //返回:,,,, </script>
实例:使用正则找出字符串中所有数字
<script> var str=' abc d aa c zz -=-=s-'; //alert(str.match(/\d+/g)); //元字符d也可以使用[-]代替,到随便哪个都行。 alert(str.match(/[-]+/g)); //返回:,,,,,,, </script>
正则是强大的字符串匹配工具,就这样简单的使用一句代码就完成了。
(3)、replace()配合正则
<script> var str='abc zaaz deaxcaa'; //将字符串中的a替换为数字 alert(str.replace('a', )); //仅仅只将第一个a替换为 //配合正则使用匹配所有a再替换 var re=/a/g; alert(str.replace(re, '')); //返回所有的a都为 </script>
实例:简单的敏感词过滤
所谓的敏感词,就是法律不允许的词语,一切非法词都可以叫做敏感词,这包括的范围就太广了,比如危害国家安全,反对宪法确立的基本原则,散步谣言,扰乱民心,扰乱社会秩序,破坏社会稳定,色情、暴力、赌博、虚假、侵害、骚扰、粗俗、猥亵或其他道德上令人反感的词,以及含有法律规定或禁止的其他内容的词语。在平时最常见也是大多数人都会用的词莫属道德上令人反感的词了,说斯文一点就是吵架时用于攻击别人的词语。这里就列举几个热门的网络词语作为例子。
<!DOCTYPE html> <html> <head> <meta charset="UTF-"> <title>JavaScript实例</title> <script> window.onload=function (){ var oBtn=document.getElementById('btn'); var oTxt=document.getElementById('txt'); var oTxt=document.getElementById('txt'); oBtn.onclick=function (){ //这里的|在正则中表示 或 的意思 var re=/元芳|萌萌哒|然并卵|毛线|二货|城会玩/g; //文本框的值等于文本框的值过滤掉敏感词 oTxt.value=oTxt.value.replace(re,'***'); }; }; </script> </head> <body> <textarea id="txt" rows="" cols=""></textarea><br> <input id="btn" type="button" value="过滤"><br> <textarea id="txt" rows="" cols=""></textarea> </body> </html>
可在第一个文本框中输入一些相关语句,点击过滤按钮,查看过滤后的效果。
此外,支持正则表达式的 String 对象的方法还包括 split() 方法,可把字符串分割为字符串数组。
7、RegExp对象方法。
在JS中,RegExp对象是一个预定义了属性和方法的正则表达式对象。
(1)、test()
test() 方法用于检测一个字符串是否匹配某个模式,也就是检测指定字符串是否含有某个子串,如果字符串中含有匹配的文本,返回 true,否则返回 false。
语法:RegExpObject.test(str)
调用 RegExp 对象 re 的 test() 方法,并为它传递字符串str,与这个表示式是等价的:(re.exec(str) != null)。
实例:搜索字符串是否含有指定的字符
<script> var str='The best things in life are free, like hugs, smiles, friends, kisses, family, love and good memories.'; var re=/i/; alert(re.test(str)); //返回:true var reg=/z/; alert(reg.test(str)); //返回:false //上面的代码可以不用定义正则的变量,直接使用,将两行合并为一行。 alert(/i/.test(str)); alert(/z/.test(str)); </script>
(2)、exec()
exec() 方法用于检索字符串中的正则表达式的匹配,提取指定字符串中符合要求的子串,该方法返回一个数组,其中存放匹配的结果。如果未找到匹配,则返回 null。可以使用循环提取所有或者指定index的数据。
语法:RegExpObject.exec(str)
exec() 方法的功能非常强大,它是一个通用的方法,可以说是test() 方法的升级版,因为他不仅可以检测,而且检测到了可以直接提取结果。该方法使用起来比 test() 方法以及支持正则表达式的 String 对象的方法更为复杂。
<script> var str = 'good good study day day up'; var re = /good/; var arr = re.exec(str); console.log(arr); //控制台显示:["good"]点开后显示: "good",index ,input "good good study day day up"。 console.log(arr.index); //控制台显示: console.log(arr.input); //控制台显示:good good study day day up </script>
通过上面的实例,可以看到,如果 exec() 找到了匹配的文本,则返回一个结果数组。否则,返回 null。此数组的第 0 个元素是与正则表达式相匹配的文本,第 1 个元素是与 RegExpObject 的第 1 个子表达式相匹配的文本(如果有的话),第 2 个元素是与 RegExpObject 的第 2 个子表达式相匹配的文本(如果有的话),以此类推。
除了数组元素和 length 属性之外,exec() 方法还返回两个属性。index 属性声明的是匹配文本的第一个字符的位置。input 属性则存放的是被检索的字符串 string。我们可以看出,在调用非全局的 RegExp 对象的 exec() 方法时,返回的数组与调用方法 String.match() 返回的数组是相同的。
什么是"与子表达式相匹配的文本"?
所谓的子表达式就是正则表达式中包含在圆括号中的内容。看下面实例:
<script> var str = 'good good study day day up'; var re = /g(o+)d/; var arr = re.exec(str); console.log(arr); //显示:["good", "oo"]点开后显示: "good", "oo", index ,input: "good good study day day up" console.log(arr.length); //显示: var reg = /(o+)/; //var reg = /o+/; 只返回一个"oo",长度为 var arr = reg.exec(str); console.log(arr); //显示:["oo", "oo"]点开后显示: "oo", "oo", index ,input: "good good study day day up" console.log(arr.length); //显示: </script>
通过上例,可以看到,子表达式是一个大的表达式的一部分,并且必须用()包含起来。一个表达式可使用多个子表达式,同时还支持多层嵌套,把一个表达式划分为多个子表达式的目的是为了把那些子表达式当作一个独立的元素来使用。也就是说表达式中的子表达式可以作为整个表达式返回,也可以作为一个单独的表达式返回。所以上面的数组长度为 2。
使用子表达式是为了提取匹配的子字符串,表达式中有几个()就有几个相应的匹配字符串,顺序会依照()出现的顺序依次进行,并且()中可以使用 或"|" 进行多个选择。也就是说可以使用()对字符进行分组,并保存匹配的文本。
如果该方法使用全局匹配,则找到第一个指定字符,并存储其位置,如果再次运行 exec(),则从存储的位置(lastIndex)开始检索,并找到下一个指定字符,存储其位置。lastIndex属性是RegExp对象属性,是一个整数,标示开始下一次匹配的字符位置。看下面实例:
<script> var str = 'good good study day day up'; var re = /good/g; var arr; do{ arr = re.exec(str); console.log(arr); console.log(re.lastIndex); } while(arr !== null) /* 结果如下: 显示:["good"],点开后: "good", index , input "good good study day day up"。 lastIndex为。 显示:["good"],点开后: "good", index , input "good good study day day up"。 lastIndex为。 显示:null lastIndex为。 */ </script>
在调用非全局的 RegExp 对象的 exec() 方法时,返回的数组与调用 String.match() 返回的数组是相同的。但是,当 RegExpObject 是一个全局正则表达式时,exec() 的行为就稍微复杂一些。它会在 RegExpObject 的 lastIndex 属性指定的字符处开始检索字符串 string。当 exec() 找到了与表达式相匹配的文本时,在匹配后,它将把 RegExpObject 的 lastIndex 属性设置为匹配文本的最后一个字符的下一个位置。这就是说,可以通过反复调用 exec() 方法来遍历字符串中的所有匹配文本。当 exec() 再也找不到匹配的文本时,它将返回 null,并把 lastIndex 属性重置为 0。
通过上面实例,可以看到,当第三次循环时,找不到指定的 "good",于是返回null,lastIndex值也变成0了。找到的第一个"good"的lastIndex值为4,是匹配文本最后一个字符的下一个位置。
<script> var str = 'good good study day day up'; var re = /good/g; var arr; while((arr = re.exec(str)) != null){ console.log(arr); console.log(re.lastIndex); } /* 结果如下: 显示:["good"],点开后: "good", index , input "good good study day day up"。 lastIndex为。 显示:["good"],点开后: "good", index , input "good good study day day up"。 lastIndex为。 */ </script>
这里需要注意,如果在一个字符串中完成了一次模式匹配之后要开始检索新的字符串(仍然使用旧的re),就必须手动地把 lastIndex 属性重置为 0。
无论 RegExpObject 是否是全局模式,exec() 都会把完整的细节添加到它返回的数组中。这就是 exec() 与 String.match() 的不同之处,后者在全局模式下返回的信息要少得多。因此可以这么认为,在循环中反复地调用 exec() 方法是唯一一种获得全局模式的完整模式匹配信息的方法。
(3)、compile
compile() 方法用于在脚本执行过程中编译正则表达式,也可用于改变和重新编译正则表达式。主要作用是改变当前(re)匹配模式。
语法:RegExpObject.compile(模式, 修饰符)
模式就是正则表达式,修饰符用于规定匹配的类型,g匹配全局,i忽略大小写,gi全局匹配忽略大小写。
该方法是改变匹配模式时使用的,一般情况下,能用到的地方很少。
实例:在全局中忽略大小写 搜索"day",并用 "天" 替换,然后通过compile()方法,改变正则表达式,用 "日" 替换 "Today" 或 "day"。
<script> var str = 'Today is a beautiful day, Day day happy!'; var re = /day/gi; var str = str.replace(re, '天'); console.log(str); //输出:To天 is a beautiful 天, 天 天 happy! reg = /(to)?day/gi; reg.compile(reg); str = str.replace(reg, '日'); console.log(str); //输出:日 is a beautiful 日, 日 日 happy! </script>
8、正規應用。
正規表示式也叫規則表達式,所以在寫作時,和寫JS的流程一樣,先慮再寫。最重要的就是,要搞清楚他所要表達的規則,先仔細端詳其外表,看他到底長的什麼模樣,也就是以什麼樣的格式存在,再根據這種格式去寫表達式,看是否能達到我們預期的目的,如果未達到,其實一般情況下直接將格式描述成表達式,都不會達到預期的效果,好在我們的主框架已經有了,我們只需要知道是什麼地方出錯了,什麼地方沒有達到預期,就可以很簡單的在這個框架基礎上稍加修改,最後就是完美的表達式了。例如要寫一個驗證手機號碼的正規表達式,手機號碼大家都知道是11位,全部為數字,而且開頭是1,緊跟著的2位,因為運營商不同,可有多種組合,後面8位是任意數字,所以我們就可以規定開頭必須為1,後面2位根據各運營商提供的不同組合進行限定,最後再輸入8位任意數字。這樣主框架就算完成了,但是手機號碼也有特殊情況,例如移動給手機號碼前邊加上86依然可以使用,必要的時候我們還需要把這種情況考慮進去,不然用戶輸入了自己的手機手機號碼給前邊加了個86,然後點擊提及,系統"啪" 彈出一個窗口,你輸入的是毛線,系統不識別,這樣就鬧笑話了,所以再只需要對框架做出修改,把這種情況考慮進去,就大功告成了。
這麼說起來正規表示式貌似很簡單的樣子,其實挺難的,why are you so diao?歸根究底就是這種一般人很難看懂的表達方式,自己當時寫的時候很明白表達的是什麼,過段時間回頭,哎喲我去,怎麼不認識了。其實這是一個熟能生巧的過程,記得有篇課文中寫到「好記性不如爛筆