正則 理解這些點就夠了

不是徹底的正則手冊,只記錄一些重要的,容易有誤解的點

定義

正則表達式經過字面量形式或RegExp構造函數形式定義git

const pattern=/\d/g
//或
const pattern = new RegExp('\d','g')

通常使用字面量形式,構造函數形式用在正則表達式在運行時才能肯定下的狀況,例如github

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

另外一方面:字符串中反斜槓有別的含義,要想表示\d等要使用兩個反斜槓來轉義\\d*正則表達式

反斜槓

在正則表達式中反斜槓有重要的含義數組

  1. 是用來轉義有特殊含義的字符,好比 [、^、.
要想只匹配.com 須要 /\.com/.test('.com')
  1. 預約的字符類以\開始,好比 d w s

而在字符串中反斜槓一樣是一個轉義字符,n r t函數

要想在字符串中表示須要兩個 \spa

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

()、[]與|

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

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

對於/[a|b]/呢?

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

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

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

從上面能夠看到,圓括號中的|是或的意思,表示要匹配()以|分割的兩邊的總體,注意是總體ci

例子:

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

分組和捕獲

上面只是介紹了圓括號中存在|時需注意的點,這裏重點說一下圓括號

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

  1. 分組

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

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

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

捕獲是一個強大的功能,也是不少時候咱們使用正則的緣由,一樣以()來表示

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

<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"

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

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把邊界替換成,

exec()、match()與g標記的故事

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

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

在有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"]

replace()

對於字符串的replace方法,重點說一下,接受的第二個參數,能夠是一個函數

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

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

"border-bottom-width".replace(/-(\w)/g,(match,capture)=>{
    return capture.toUpperCase()
})
> "borderBottomWidth"

喜歡的給個star,github,謝謝

相關文章
相關標籤/搜索