js正則驗證特殊字符「js正則表達式語法大全」

0.導引

在正文開始前,先說說正則表達式是什麼,為什麼要用正則表達式?正則表達式在我個人看來就是一個程序可以識別的規則,有了這個規則,程序就可以幫我們判斷某些字符是否符合我們的要求。但是,我們為什麼要使用正則表達式呢?下面來看個正則業務場景,來驗證一串字符是否為合法QQ號。示例如下:

/**
* 要求:一個合法的QQ號必須滿足:1、5-15位;2、全是數字;3、不以0開頭
*/

//1.在不使用正則表達式的時候,我們可能會這樣判斷QQ號的合法性
var qq="6666666a6666";         
if(qq.length>=5&&qq.length<=15&&!isNaN(qq)&&qq.charCodeAt(0)!=48){
        alert("QQ合法");
    }else{
        alert("QQ不合法")
    }
    
//2.使用正則表達式
    var qq="066336";
    var reg=/^[1-9][0-9]{4,14}$/;
    if(reg.test(qq)){
        alert("QQ合法");
    }else{
        alert("QQ不合法");
    }

從上面這個例子可以看出來使用了正則表達式的時候,我們的代碼量變少了,而且比較直觀。如果遇到非常的複雜的匹配,正則表達式的優勢就更加明顯了。

正則精要:玩轉JS正則表達式,也許只需這一篇(建議收藏)

那什麼是正則表達式呢?

1.正則定義

也就是創建正則表達式對象,可通過字面量形式或RegExp構造函數兩種形式來定義,如下所示:

// 字面量定義
const pattern=/d/g
//或 構造器定義
const pattern = new RegExp('d','g')

一般使用字面量形式,構造函數形式用在正則表達式在運行時才能確定下的情況,例如

function hasClass(ele, classname) {
    const pattern = new RegExp('(^|\s)' + classname + '(\s|$)')
    return pattern.test(ele.className)
}

注意:字符串中反斜杠有別的含義,要想表示d等要使用兩個反斜杠來轉義\d* 。

第一種通過“/正則表達式/修飾符“這種形式直接寫出來;

第二種通過「new RegExp(‘正則表達式’,’修飾符’)」創建一個RegExp對象。

其中修飾符為可選項,有三個取值分別為:g為全局匹配;i指不區分大小寫;m指多行匹配。

通過上述方式,就創建了正則表達式對象。說到RegExp對象,下面要說一下RegExp對象自帶的屬性,並不複雜,這裡我就列一下,不做展開。

正則精要:玩轉JS正則表達式,也許只需這一篇(建議收藏)

2.符號及應用解析

正則精要:玩轉JS正則表達式,也許只需這一篇(建議收藏)

1)反斜杠

在正則表達式中反斜杠有重要的含義

  • 是用來轉義有特殊含義的字符,比如 [、^、.等。例如,要想只匹配.com 需要
         /.com/.test('.com')
  • 預定的字符類以開始,比如 d w s

而在字符串中反斜杠同樣是一個轉義字符,比如結合n r t來表示換行、回車、製表位等

要想在字符串中表示出一個,則表達式中需要兩個 ,示例如下:

new RegExp("[\w\.]").toString()=='/[w.]/'

2)()、[]與|

[]:集合操作符,表示一系列字符的任意一個

例如:/[abc]/ 表示a、b、c中的任意一個能匹配就可以了

關於/[a|b]/

一個常見的誤區是感覺/[a|b]/表示要匹配a或者b,其實是a、b或者|中的任意一個

/[a|b]/.test('|') === true

/(a|b)/.test('|') ===false

關於括號()

從上面可以看到,圓括號中的|是或的意思,表示要匹配()以|分割的兩邊的整體(兩邊其中之一),注意是整體。

例子:

/(abc|abd)/.test('ab') ===false
/(abc|abd)/.test('abc') ===true
/(abc|abd)/.test('abd') ===true

3)分組與捕獲
上面只是介紹了圓括號中存在|時需注意的點,這裡重點說一下圓括號(英文狀態下的小括號())

在正則中,圓括號有兩種含義,一是用來分組,一是用來捕獲想要的值

  • 分組

()結合* ? + {} 使用時,是對圓括號內的整體進行repeat

/(ab)+/ 匹配一個或多個ab

/(ab)+|(cd)+/ 匹配一個或多個 ab或cd
  • 捕獲

捕獲是一個強大的功能,也是很多時候我們使用正則的原因,同樣以()來表示

例子:找出樣式中的透明度值

<div id="opacity" style="opacity:0.5;filter:alpha(opacity=50);">

function getOpacity(elem) {
    var filter = elem.style.filter;
    if(filter){
        return filter.indexOf("opacity=") >= 0 ?(parseFloat(filter.match(/opacity=([^)]*)/)[1]) / 100) + "" : "" 
    }
    return elem.style.opacity
}

捕獲主要結合exec()、match() 和 g標記使用,下面會介紹

需要強調的是,因為分組和捕獲一樣使用(),所以,在一個正則表達式中既有用於分組的(),也有用於捕獲的()時,對於分組部分,可以加上?:,這樣,結果集就只包含我們想要捕獲的部分。

示例如下:

'<div>hahahahah<div>'.match(/(<[^>]+>)([^<]+)/)
> [ <div>hahahahah , <div> , hahahahah ] //兩個捕獲

如果我們只對標籤內的文本感興趣

'<div>hahahahah<div>'.match(/(?:<[^>]+>)([^<]+)/)
> [ <div>hahahahah , hahahahah ] //對於<div>,我們不關心,就不要了

說到?: 就要提一下長得差不多的 ?= 和 ?!

?= 表示後面必須跟着某些東西,並且結果中不包含?=指定的部分,並且不捕獲

?! 表示後面必須不跟着某些東西

對比看一下

/a(?:b)/.exec('abc')
> ["ab", index: 0, input: "abc"] //注意匹配的是"ab"

/a(?=b)/.exec('abc')
> ["a", index: 0, input: "abc"] //注意匹配的只是"a"

/a(?!b)/.exec('abc')
> null //沒有匹配的,返回的是null

再看個例子,數字字符串轉千分位

function formatNumber(str) {
  return str.replace(/B(?=(d{3})+$)/g, ',')
}
formatNumber("123456789")
> 1,234,567,890

解釋:

  1. B表示除了字符串首字母之前的邊界,比如1和2之間的邊界,2和3之間的邊界等
  2. 後面()中的?=(d{3})+$表示上面提到的那些邊界後面必須跟着3N個數字直到字符串尾部
  3. g表示全局匹配,即每個上面說的邊界都要檢測2,如果符合,replace把邊界替換成,

4)exec()、match()與g標記

exec()和match()都是返回數組,結果集中包含捕獲的內容

在正則中不包含g時,exec()和match()返回的結果集是一樣的,數組中依次是 整個匹配的字符串、依次的()指定的要捕獲的部分

正則精要:玩轉JS正則表達式,也許只需這一篇(建議收藏)

在有g的時候,match()返回的數組中的每一項是依次匹配到的整體字符串,不包含每個匹配中捕獲到的內容

對比來看

"p123 q123".match(/b[a-z]+(d+)/)
> ["p123", "123", index: 0, input: "p123 q123"]

"p123 q123".match(/b[a-z]+(d+)/g)
> ["p123", "q123"]

可以看到加上g後,返回的數組就只有匹配項了

那麼,即想匹配全部,又想獲取到捕獲怎麼辦呢?

while與exec()結合

let pattern=/b[a-z]+(d+)/g
let str='p123 q123'
let match
while((match=pattern.exec(str)) !=null){
    console.log(match)
}

> ["p123", "123", index: 0, input: "p123 q123"]
  ["q123", "123", index: 5, input: "p123 q123"]

5)replace()

對於字符串的replace方法,重點說一下,其第二個參數,可是一個函數。

對於str.replace(/xxxxx/g,function(){})

函數在每次前面的正則匹配成功時都會執行,函數的參數依次是,完整的匹配文本、依次的捕獲部分、當前匹配的索引、原始字符串

"border-bottom-width".replace(/-(w)/g,function(match,capture){
    return ";"+capture.toUpperCase()
})
> "border;Bottom;Width"

注意,有人可能把其中的第二個函數參數改寫成箭頭函數,如(..)=>{..}則可能會出錯,需要當心。

正則精要:玩轉JS正則表達式,也許只需這一篇(建議收藏)

3.應用精要

有了上面的認知和解析,這裡再總結一下正則對象(包括兩種方式創建的對象)的主要方法。

1.test()

檢索字符串中指定的值。返回 true 或 false。這個是我們平時最常用的方法。

 var reg=/hello w{3,12}/;
 alert(reg.test('hello js'));//false
 alert(reg.test('hello javascript'));//true

2.exec()

檢索字符串中指定的值。匹配成功返回一個數組,匹配失敗返回null。

var reg=/hello/;
console.log(reg.exec('hellojs'));//['hello']
console.log(reg.exec('javascript'));//null

3.compile()

compile() 方法用於改變正則。compile() 既可以改變檢索模式,也可以添加或刪除第二個參數。


var reg=/hello/;
console.log(reg.exec('hellojs'));//['hello']
reg.compile('Hello');
console.log(reg.exec('hellojs'));//null
reg.compile('Hello','i');
console.log(reg.exec('hellojs'));//['hello']

正則表達式拓展

除了RegExp對象提供方法之外,String對象也提供了四個方法來使用正則表達式,在使用JavaScript時,也常用到。

1.match()

在字符串內檢索指定的值,匹配成功返回存放匹配結果的數組,否則返回null。這裡需要注意的一點事,如果沒有設置全局匹配g,返回的數組只存第一個成功匹配的值。


var reg1=/javascript/i;
var reg2=/javascript/ig;
console.log('hello Javascript Javascript Javascript'.match(reg1));
//['Javascript']
console.log('hello Javascript Javascript Javascript'.match(reg2));
//['Javascript','Javascript','Javascript']

2.search()

在字符串內檢索指定的值,匹配成功返回第一個匹配成功的字符串片段開始的位置,否則返回-1。

var reg=/javascript/i;
console.log('hello Javascript Javascript Javascript'.search(reg));//6

3.replace()

替換與正則表達式匹配的子串,並返回替換後的字符串。在不設置全局匹配g的時候,只替換第一個匹配成功的字符串片段。

var reg1=/javascript/i;
var reg2=/javascript/ig;
console.log('hello Javascript Javascript Javascript'.replace(reg1,'js'));
//hello js Javascript Javascript
console.log('hello Javascript Javascript Javascript'.replace(reg2,'js'));
//hello js js js

4.split()

把一個字符串分割成字符串數組。

var reg=/1[2,3]8/;
console.log('hello128Javascript138Javascript178Javascript'.split(reg));
//['hello','Javascript','Javascript178Javascript']

4.兩例實戰

第一次接觸正則表達式同學們,可能被這個正則表達式的規則弄得迷迷糊糊的,根本無從下手。小編我第一次學這個正則表達式的時候,也是稀里糊塗,什麼元字符、量詞完全不知道什麼東西,雲里霧裡的。後面小編細細研究了一下,總結一套方法,希望可以幫助大家。

關於正則表達式書寫規則,可查看w3school,上面說的很清楚了,我就不貼出來了。我就闡述一下我寫正則表達式的思路。

其實正則表達式都可以拆成一個或多個(取值範圍+量詞)這樣的組合。針對每個組合我們根據JS正則表達式的規則翻譯一遍,然後將每個組合重新拼接一下就好了。下面我們舉個例子來試一下,看看這個方法行不行。

驗證QQ號的合法性

合法qq號規則:1、5-15位;2、全是數字;3、不以0開頭

第一步:拆成(取值範圍+量詞)這樣的組合

根據QQ號的驗證規則,我們可以拆成兩個(取值範圍+量詞)的組合。分別是:

1.(1~9的數字,1個);2.(0~9的數字,4~14個)
第二步:根據正則表達式規則翻譯(取值範圍+量詞)
1.(1~9的數字,1個)     =>   [1-9]{1}或者[1-9]
2.(0~9的數字,4~14個)  =>   [0-9]{4,14}
第三步:將翻譯好的(取值範圍+量詞)組合進行拼接

初學者可能在拼接這一步會犯一個錯誤,可能會組合拼接成這個樣子/[1-9]{1}[0-9]{4,14}/或者簡寫翻譯成/[1-9] [0-9]{4,14}/這些都不對的。調用test()方法的時候,你會發現只要一段字符串中有符合正則表達式的字符串片段都會返回true,童鞋們可以試一下。

var reg=/[1-9][0-9]{4,14}/;
alert(reg.test('0589563'));
//true,雖然有0,但是'589563'片段符合
alert(reg.test('168876726736788999'));
//true,這個字符串長度超出15位,達到18位,但是有符合的字符串片段

正確的寫法應該是這樣的:

/^[1-9][0-9]{4,14}$/(用^和$指定起止位置)

下面我們看一個複雜點的例子:

驗證國內電話號碼

0555-6581752、021-86128488

第一步:拆成(取值範圍+量詞)這樣的組合

這裡會拆成兩個大組合:

1、(數字0,1個)+(數字0~9,3個)+("-",1個)+(數字1~9,1個)+(數0~9,6個)
2、(數字0,1個)+(數字0~9,2個)+("-",1個)+(數字1~9,1個)+(數0~9,7個)
第二步:根據正則表達式規則翻譯(取值範圍+量詞)
1、([0-0],{1})+([0-9],{3})+"-"+([1,9],{1})+([0,9],{6})
2、([0-0],{1})+([0-9],{2})+"-"+([1,9],{1})+([0,9],{7})
第三步:將翻譯好的(取值範圍+量詞)組合進行拼接

這裡我們先拼接一個大組合,然後再將大組合拼接起來

1、0[0-9]{3}-[1-9][0-9]{6}
2、0[0-9]{2}-[1-9][0-9]{7}

最後拼接為:

/(^0[0-9]{3}-[1-9][0-9]{6}$)|(^0[0-9]{2}-[1-9][0-9]{7}$)/

最後

正則表達式並不難,懂了其中的道道和套路——所謂的核心和精要之後,一切都會變得簡單。

另外,說點題外話——網上不乏一些文章記錄一些常用的正則表達式,然後新手前端在使用正則表達式的時候都會直接拿來就用。在這裡我想說一下自己的看法,這些所謂記錄常用的正則表達式文章並非完全都是正確的,有不少都是錯的,也可能是無心的,就像我們經常在網上看到的示例,你怎麼也跑不通。所以同學們在日後使用的過程盡量自己寫正則表達式,多寫寫練練和總結,實在不會了可以去參考一下,但真的不要照搬下來。咱不說這種會影響自己成長的話,咱就說你抄的一定都是對的嗎?多動手,多思考一下,總沒有壞處的。

原創文章,作者:投稿專員,如若轉載,請註明出處:https://www.506064.com/zh-hk/n/210894.html

(0)
打賞 微信掃一掃 微信掃一掃 支付寶掃一掃 支付寶掃一掃
投稿專員的頭像投稿專員
上一篇 2024-12-08 16:25
下一篇 2024-12-08 16:25

相關推薦

發表回復

登錄後才能評論