從RegExp.prototype.test()開始說正則的lastIndex屬性

故事的開始是這樣的:程序員

clipboard.png

須要作的就是爲這個列表加上搜索功能。爲了更簡單的說明問題,這個問題最後就至關於對原始
name數組進行一次匹配過濾,因而想固然的有了相似下面的代碼:正則表達式

var  ori=['李同窗1','李同窗2','李同窗3','劉同窗']
var searchText='李'

var reg = new RegExp('.*'+searchText+'.*', 'g')
var newArr = ori.filter(function(value) {
  return reg.test(value)
})
console.log(newArr)       //[ '李同窗1', '李同窗3' ]

這裏假設咱們的搜索字符串爲‘李’,預期過濾事後的新數組newArr應該爲['李同窗1','李同窗2','李同窗3'],可打印出來的結果只有2個,跳過了數組中的第二個元素。這裏隱藏了什麼問題?爲了說清楚這個問題,要從正則表達式自己的一個屬性lastIndex提及。數組

regexp.lastIndex

mdn的文檔說的很清楚,lastIndex是正則表達式一個可讀可寫的整形屬性,表示下次正則匹配的起始索引。只有在正則自己使用全局匹配 ‘g’ 時,該屬性纔會被設置而且起做用。且該屬性的設置遵循下面的規則:spa

  • 若是 lastIndex 大於字符串的長度,則 regexp.test 和 regexp.exec 將會匹配失敗,而後 lastIndex 被設置爲 0。翻譯

  • 若是 lastIndex 等於字符串的長度,且該正則表達式匹配空字符串,則該正則表達式匹配從 lastIndex 開始的字符串。code

  • 若是 lastIndex 等於字符串的長度,且該正則表達式不匹配空字符串 ,則該正則表達式不匹配字符串,lastIndex 被重置爲 0.。regexp

  • 不然,lastIndex 被設置爲緊隨最近一次成功匹配的下一個位置。blog

規則看的很暈,其實本身試一下就知道了。回顧上面的問題,咱們打印一下lastIndex屬性:索引

var  ori=['李同窗1','李同窗2','李同窗3','劉同窗1']
var searchText='李'

var reg = new RegExp('.*'+searchText+'.*','g')
var newArr = ori.filter(function(value) {
  console.log(reg.lastIndex)
  return reg.test(value)
})
console.log(newArr)

//執行的結果爲 0 4 0 4  [ '李同窗1', '李同窗3' ]

由上面打印的結果,問題出在哪了已經很明顯了,對於數組中第二個元素的匹配,是從索引爲4開始(索引的結果還與 .* 默認的貪婪模式匹配有關,這裏不作贅述),這裏固然不匹配,符合上述第三個規則,知道了這一點,咱們就能夠很靈活的改正這個問題:ip

var  ori=['李同窗1','李同窗2','李同窗3','劉同窗1']
var searchText='李'

//最直接的就是取消正則的全局匹配標誌
var reg = new RegExp('.*'+searchText+'.*?')
var newArr = ori.filter(function(value) {
  return reg.test(value)
})

//把起始索引改回來
var reg = new RegExp('.*'+searchText+'.*?','g')
var newArr = ori.filter(function(value) {
  reg.lastIndex=0
  return reg.test(value)
})

//還能夠忽略全部名稱的第一位進行匹配
var reg = new RegExp('.*'+searchText+'.*?','g')
var newArr = ori.filter(function(value) {
  reg.lastIndex=1
  return reg.test(value)
})

最後一個細節,在非全局匹配模式下,lastIndex屬性是不起做用的,即便設置這個屬性值,匹配也會從起始位置開始。

結語

其實解決這個問題,最開始的時候並無直擊問題的核心,只知道test()方法是返回一個布爾值,對lastIndex屬性也沒有太多瞭解,也就無法意識到這一層,但我仍是去mdn看了一下test()的文檔,默認看的中文版,很不幸中文版的翻譯裏恰好少了正則全局標誌下使用test()這一節,因而更堅決此方法不就是返回個布爾值的論斷。結果多繞了幾彎,一怒之下就跑去補充了mdn關於test()方法的中文翻譯。對於一個初級程序員的平常開發來講,不少時候遇到的‘意外’,都是相關內容知道的不全面,這時候參考文檔通常都是能夠發現問題。

相關文章
相關標籤/搜索