簡單學習 JavaScript 正規表示式

誰誰發表於2016-11-04

為什麼要用正規表示式

簡單的說:我們與字串接觸的頻率非常之高,正規表示式可以極大的提高複雜文字分析的效率,快速匹配出複雜的字串。

建立一個正規表示式

  1. 直接量語法(字面量)

    var expression = /pattern/flags ;
    //pattern 是要匹配的字串模式
    //flags用來標記正規表示式的行為: i 不區分大小寫;g 表示全域性搜尋 ;m 表示多行模式
    var reg = /ab/i ,表示匹配 字串 `ab` 不區分大小寫
  2. 呼叫RegExp物件的建構函式

    //RegExp 是js中一個內建的物件,是正規表示式的縮寫
    var expression = new RegExp(pattern,flags)
    //flags 和直接量語法一致
    //pattern 可以是字串模式,也可以是一個標準的正規表示式,後者必須省略 flags
    //可以寫成var reg = new RegExp(`ab`,`i`)  或者var reg = new RegExp(/ab/i)
    //不能寫成 var reg = new RegExp(/ab/,`i`)

ES5中規定:使用直接量必須像直接呼叫RegExp建構函式一樣,每次都建立一個新的RegExp例項,所以
上面2種方式建立正規表示式,除了過程不一樣,效果是一樣的。

RegExp每個例項都有如下屬性:

  1. global:布林值,表示例項是否設定了 g 標誌

  2. ignoreCase:布林值,表示是否設定了 i 標誌

  3. multiLine:布林值,表示是否設定了m 標誌

  4. source:返回建立RegExp物件例項時指定的表示式純文字字串。不包含後面的標誌

  5. lastIndex:整數,表示例項在接下來的一次搜尋匹配項的開始位置,預設從0開始

使用正規表示式的例項方法

RegExp.prototype.exec()

exec() 方法為指定的一段字串執行搜尋匹配操作,返回包含第一個匹配項的陣列,regexObj.exec(str) ,沒有匹配到則返回 null,返回的陣列是Array的例項,而且返回值還包含另外2個屬性:index: 匹配到的字元位於原始字串的基於0的索引值input: 原始字串`

var myRe = /ab*/g;
var str = `abbcdefabh`;
var oo = myRe.exec(str)
// oo ==> ["abb"] 
// oo.index ==> 0 
// myRe.lastIndex ==> 0
// 從返回結果可以看出來,即使我們設定了全域性的g,exec也不會一次性返回所有的匹配結果
// 因為其定義就是  返回包含`第一個匹配項`的陣列,只要第一次匹配到,後面就不繼續執行
// 我們再執行一次
oo = myRe.exec(str)
// oo ==> ["ab"] 
// oo.index ==> 3 
// myRe.lastIndex ==> 3
// 再次執行之後可以看到 匹配項和一些屬性值都發生了變化,說明 這次並不是從頭開始

官方說明:當正規表示式使用 “g” 標誌時,可以多次執行 exec 方法來查詢同一個字串中的成功匹配。當你這樣做時,查詢將從正規表示式的 lastIndex 屬性指定的位置開始(也就是說下次的查詢將在上次匹配成功後面開始匹配,而且會迴圈,在匹配不到的時候,會從頭開始)。(test() 也會更新 lastIndex 屬性)。
不加”g” 標誌的時候,每次都是從 0 開始,所以各種屬性也不會改變

exec() 方法還有一個重要的作用:匹配捕獲組

var str= "cat2,hat8" ;
var reg=/c(at)/ ;  
console.info(reg.exec(str));//執行返回   ["cat2", "at"]
加了捕獲組的時候,結果會把捕獲組一起返回,不加則沒有,支援多個捕獲組

注意 IEjavascriptlastIndex 設計上存在偏差,沒加g的情況下也會每次發生改變,慎用

RegExp.prototype.test()
接收一個字串引數,regexObj.exec(str),匹配返回true,否則false

RegExp.prototype.toString() ( RegExp.prototype.toLocaleString())

RegExp 物件覆蓋了 Object 物件的 toString() 方法,並沒有繼承 Object.prototype.toString()。對於 RegExp 物件,toString 方法返回一個該正規表示式的字面量

myExp = new RegExp("a+b+c");
alert(myExp.toString());       // 顯示 "/a+b+c/"

foo = new RegExp("bar", "g");
alert(foo.toString());         // 顯示 "/bar/g"

正規表示式在 String 的應用

match
一個在字串中執行查詢匹配的String方法,它返回一個陣列或者在未匹配到時返回null

var oo = `121212`.match(/1/g)
oo
//["1", "1", "1"]
var oo = `121212`.match(/1/)
oo
//["1"]

replace
一個在字串中執行查詢匹配的String方法,並且使用替換字串替換掉匹配到的子字串。

`121212`.replace(/1/g,`,`)
//",2,2,2"

split
一個使用正規表示式或者一個固定字串分隔一個字串,並將分隔後的子字串儲存到陣列中的String方法。

//以數字分割字串
`a1b2c33d4`.split(/d*/)
//["a", "b", "c", "d", ""]

search
一個在字串中測試匹配的String方法,它返回匹配到的位置索引,或者在失敗時返回-1。

//查詢連續2個數字的位置
`a1b2c33d4`.search(/(d){2}/)
// 5

小練習

把一串數字字串千分位方式(逗號)轉化成金額符號

分析要點:

  1. 金額的千分位是從右往左,每3位加一個逗號,但是正規表示式裡面從右往左不是很方便,所以第一步要把數字顛倒過來,字串並沒有直接的顛倒方法,陣列有,Array.prototype.reverse.call([1,2,3,4]) ==>[4, 3, 2, 1],字串轉陣列也是很方便的,String.prototype.split.call(`1234`,``) ==> ["1", "2", "3", "4"]

  2. 再把顛倒的陣列拼接成字串 Array.prototype.join.call([4,3,2,1],``)==> 4321

  3. 小數點後面的不需要處理,所以我們要獲取 String.prototype.split.call(`12345.678`,`.`)[1] ==> 12345 因為我們這裡已經反轉了,所以真正要轉化的數字在第二個

  4. 前面都是準備工作,現在需要用正規表示式處理字串,匹配連續的3位數字分割成陣列 d{3} 表示連續3個數字 String.prototype.match.call(`1234`,/d{3}/) ==> ["123"],這裡把後面的一位數字和2位數字直接忽略了,並且沒有全域性匹配,所以我們要補充一下。

    String.prototype.match.call(`1234567891`,/d{3}|d{2}|d{1}/g)
    //["123", "456", "789", "1"]
  1. 最後就把陣列用逗號連線,在用小數點和之前的小數位加在一起,再像第一步那樣反轉一下順序就可以了。

例子程式碼

function money_thousandth (str){
    //先檢查是不是符合數字型別
    if(isNaN(str)){
        return `必須傳入數字或者數字字串`
    }
    str = str.toString();
    //反轉順序並分割小數點
    var arr = str.split(``).reverse().join(``).split(`.`);
    //全域性優先匹配連續的3位數字,或者2位,或者1位
    var reg = /d{3}|d{2}|d{1}/g;
    //有小數點取第二位,沒有則取第一位
    var thousand = arr[1] || arr[0] ;
    //分割陣列 
    var result_arr =  thousand.match(reg);
    //逗號拼接分割好的金額
    var result_str = result_arr.join(",");
    //與小數點前面加起來
    var result = arr[1] ?   arr[0] + `.`+ result_str  : result_str
    //返回顛倒的數字字串
    return result.split(``).reverse().join(``)
}
money_thousandth(1234567898.12)
//"1,234,567,898.12"
money_thousandth(`1234567898.12`)
//"1,234,567,898.12"

點選檢視正規表示式常用語法

相關文章