本文簡單介紹了正則表達式的元字符,和 JavaScript 提供的兩個和正則表達式有關的方法:
RegExp.prototype.exec()
和String.prototype.replace()
。html
正則表達式一般被用來檢索、替換那些符合某個模式(規則)的文本。java
正則表達式爲了描述一個規則,每每須要用到大量的元字符,這些元字符要記下來並靈活運用,須要耗費不少的精力,而通常實際開發中卻不多用到正則表達式。此外爲了保證複雜正則表達式是符合需求的,須要進行大量的字符串測試。因此這也是遇到須要用到複雜正則表達式實現的需求時,程序員表示很是難受(awsl)的緣由。程序員
儘管可能會用得比較少,但在某些場景下,使用正則表達式是最好的選擇,並且面試也可能會問到,因此仍是要好好掌握一些比較基本的用法的。es6
由於不是本文的重點,並且知識點過多,這裏只會 簡單描述一部分的元字符。若是你想系統地學習,能夠閱讀文末提供的參考資料。面試
字符 | 含義 |
---|---|
\ | 轉義字符 |
^ | 匹配輸入開始 |
$ | 匹配輸入結束 |
* | 匹配前一個表達式 0到屢次。等價於{0,} |
+ | 匹配前一個表達式 1到屢次。等價於{1,} |
? | 匹配前一餓表達式 0或1次。等價於{0,1} |
. | 匹配換行符外的任何單字符 |
(reg) | 捕獲組,會捕獲括號裏面的匹配項 reg。 |
(?:reg) | 匹配 'reg' 但不捕獲匹配項。當咱們須要將一段表達式做爲一個總體,但又不想它被捕獲的時候,就能夠這樣寫。好比 (?:ab)+ |
x(?=y) | 專業術語爲 「先行斷言」。當 x 後面有 y 時,才匹配 x。匹配的子串將不會包含 y。 |
(?<=x)y | 「後行斷言」,和上一條同理。 |
x(?!y) | 「正向否認查找」。匹配一個 x 後面沒有 y 的 x |
x|y | 匹配 x 或 y |
{n} | 匹配前面一個字符(也能夠是圓括號圍起來的一個子串) n 次,n必須爲正整數。 |
{n, m} | 匹配前面的字符 n - m 次。m 能夠省略,表示匹配 n 次或更多。m 必須 大於或等於 n。若是 n 爲 0,就是匹配前面字符0次,至關於這個子串被忽略。 |
[xyz] | 字符集合。匹配方括號內的任意字符。咱們也能夠經過 - 來指定字符範圍,好比 [a-d] 等價於 [abcd],[1-4] 等價於 [1234],[\u4e00-\u9fa5] 則是匹配一個漢字。. 和 * 在方括號內沒有特殊含義,不須要進行轉義。 |
[\xyz] | 匹配沒有包含在方括號裏任何字符的字符。 |
[\b] | 匹配一個退格符 |
\b | 匹配一個詞的邊界,匹配位於邊界的單詞字符。。\b 並不能匹配一個字符。如 \bm 能夠匹配 moon ,oo\b 不能匹配 moon。 |
\B | 匹配非單詞邊界。如 \Boo 匹配 'noonday' 的 oo。 |
\d | 匹配一個數字,等價於 [0-9] |
\D | 匹配非數字。通常大寫表示對應小寫的特殊字符的反面。 |
\s | 匹配空白符 |
\S | 匹配非空白符 |
\w | 匹配一個單字符(字母、數字或下劃線),等同於 [A-Za-z0-9_],注意這個是匹配不了漢字的。 |
\W | 與 \w 相反 |
\count | 這裏的 count 代指一個正整數,等同於第n個子捕獲匹配的子字符串(捕獲的數目以左括號計數)。這個其實挺有趣的。如 /a(b)(c)d\2\1/ 等同於 /a(b)(c)dcb/ |
| | 分支條件 |
正則表達式默認使用 貪婪匹配,即匹配儘量多的字符。但有時候咱們但願能夠匹配儘量少的字符,即 懶惰匹配,咱們能夠在限定符(*、+、?、{n,m}這些指定重複數量的特殊字符)的後面添加 ?
表示。如 a*?
表示匹配 a 重複任意次,但儘量少。正則表達式
使用複雜的正則表達式會遇到的問題是,沒法保證寫出的正則表達式是適用於全部對應的狀況,這就須要咱們作足夠多的測試。此外,正則表達式不是很好理解,須要作一些註釋才能直到它作了什麼事,一些語言容許在正則表達式使用註釋語法,但 js 並不支持。數組
若是是新手,建議使用 RegExp.prototype.exec()
方法一個個進行測試來加深理解。bash
ES6 中,正則表達式的功能獲得了增強,並提供了更多的方法,本文不會討論這些新方法。ide
方法 | 描述 |
---|---|
exec | 一個在字符串中執行查找匹配的RegExp方法,它返回一個數組(未匹配到則返回null)。 |
test | 一個在字符串中測試是否匹配的RegExp方法,它返回true或false。 |
match | 一個在字符串中執行查找匹配的String方法,它返回一個數組或者在未匹配到時返回null。 |
search | 一個在字符串中測試匹配的String方法,它返回匹配到的位置索引,或者在失敗時返回-1。 |
replace | 一個在字符串中執行查找匹配的String方法,而且使用替換字符串替換掉匹配到的子字符串。 |
split | 一個使用正則表達式或者一個固定字符串分隔一個字符串,並將分隔後的子字符串存儲到數組中的String方法。 |
這些方法爲 String 或 RegExp 對象的方法。函數
正則表達式的 exec() 方法,是爲 捕獲組 而設計的。
const pattern = /a(bc(1))(de)/g
const text = `-abc1de-`;
const matches = pattern.exec(text);
複製代碼
exec() 方法若是匹配成功,會返回一個 數組。這個數組除了數字索引外,還有一些其餘的屬性。若是匹配失敗,會返回 null。
/(?<year>\d{4})-(?<month>\d{2})-(?<day>\d{2})/
, 匹配成功後, matches.groups.year 的值就是 matches[1]。若是正則表達式帶上了 g 標誌,每一次執行 exec() 方法,pattern(RegExp 對象) 的 lastIndex 都會變化,若是匹配成功,爲匹配字符串的後一個索引位置。這個 lastIndex 指定了輸入字符串的匹配起始值。剛建立的 RegExp 對象的 lastIndex 爲 0,你能夠對其進行修改。若是沒有匹配到,lastIndex 會被設置爲 0。
replace() 方法返回一個由替換值(replacement)替換一些或全部匹配的模式(pattern)後的新字符串。
str.replace(regexp|substr, newSubStr|function)
複製代碼
第一個參數能夠是字符串或正則表達式,若是提供的是字符串,只會替換第一個子字符串。若是想替換全部子字符串,須要提供一個指定了 g 的正則表達式。
第二個參數能夠是字符串或函數。
若是是字符串,可使用一些特殊的 字符序列:
字符序列 | 替換文本 |
---|---|
$$ | $(用於轉義) |
$& | 匹配整個模式的子串,與 RegExp.lastMatch(非標準特性) 的值相等。 |
$` | 當前匹配的子串 左邊 的內容,與RepExp.leftContext(非標準屬性,請勿在生產環境中使用) 的值相同。 |
$' | 當前匹配的子串 右邊 的內容,與 RegExp.rightContentx(非標準屬性) 的值相同。 |
$n | 這裏 n 取值爲 1 - 99。位數只有1個的話,能夠加上前導零,如 $04 等同於 $4 。$n 其實等價於 RegExp.prototype.exec() 返回的數組,但不一樣點在於, $0 是無效的,得使用 $& 。n 超出了捕獲組的索引範圍,會替換爲 "$n"(即失去特殊轉換的效果)。 |
下面的寫法,能夠交換兩個單詞的位置。
'bar foo'.replace( /(...) (...)/, '$2 $1' )
// -> 'foo bar'
複製代碼
若是第二個參數也能夠是函數,這個函數接收多個參數:
function (match[,p1, p2, ..., pn], offset, string)
複製代碼
咱們能夠用它來實現 簡單的模版引擎(只能替換文本):
const pattern = /\{\{\s*(.*?)\s*\}\}/g,
const data = {
name: '李田所',
age: 24,
job: '學生'
}
const text = `我是{{name}},今年{{ age }}歲,是個{{ job}}。`;
const renderResult = text.replace(pattern, function(match, p1, offset, string) {
return data[p1]
})
console.log(renderResult)
// -> 我是李田所,今年24歲,是個學生。
複製代碼