[JS] 正則表達式(Regular Expression, regex)
'str'.match(/[0-9]+/); // 1 次以上的數字,等同於 "\d"
'str'.match(/[A-Za-z]+/); // 1 次以上的英文字
'str'.match(/[A-Za-z0-9_]+/); // 1 次以上的英數字含底線,等同於 "\w"
'str'.match(/.+/); // 1 次以上的任意字元
* 表示前一個字元可以是 0 個或多個,例如 /ab*c/,因此 ac, abc, abbbbc 都符合規則。
+ 表示前一個字元可以是 1 個或多個,例如 /a+b/ ,ab, aaaaab 都符合規則。
? 表示前一個字元可以是 0 個或 1 個
^ 匹配輸入的開頭,例如 /^a/ , a dog 會符合,但 cats 中的 a 不會。
$ 匹配輸入的結尾,例如 /t$/,eat 會符合,但 eaten 中的 t 不會。
. 用來表示任意字元
regex = \$(?!\{) // 使用 negative lookahead (?!ABC) 找出所有 $ 但不是 ${ 的字
- 👍 Regular expressions @ JavaScript.info
- Regular Expression @ MDN - JavaScript Guides
- Regular Expression @ MDN - Reference
- I hate regex: 可以找到許多常用的 regex 範例
- 常用正規表達式
建立正規式
正則表達式的規則稱作 pattern。在 JavaScript 中可以透過 Regular expression literals 的方式或建構式的方式來建立 regular expressions pattern:
Regular expression literals
/**
* Regular expression literals: script 載入時即編譯
* 當 pattern 不會改變時,使用此方式定義 pattern 效能較好。
**/
var re = /ab+c/;
Function Constructor
/**
* Function constructor for RegExp object: 程式執行過程才會被編譯
* 效能較差,適合用在 regular expression pattern 可能會改變時使用
**/
var re = new RegExp('ab+c');
var myRe = new RegExp('d(b+)d', 'g');
Regular expression literals
效能較好,適合 pattern 不會改變的情況;Function Constructor
效能較差,適合用在 pattern 可能動態改變的情況。
使用正規式
在 JavaScript 中可以使用正規式的函式包含
RegExp.prototype.test()
:搜尋字串中是否有符合的部分,回傳true
/false
。RegExp.prototype.exec()
:以陣列回傳字串中匹配到的部分,否則回傳null
。String.prototype.match()
:以陣列回傳字串中匹配到的部分,否則回傳null
。String.prototype.replace()
:尋找字串中匹配的部分,並取代之。String.prototype.search()
:尋找字串中是否有符合的部分,有的話回傳 index,否則回傳-1
。String.prototype.split()
:在字串根據匹配到的項目拆成陣列。
簡單來說,當你想要看字串是否包含某 pattern 時,使用
test
或search
;想要更多的資訊(花較多耗效能),則使用exec
或match
。
String.prototype.replace():取代內容
使用 String.prototype.replace(regex|substr, newSubstr)
來置換內容,這個方法會回傳置換後的新字串,不會改變原本的字串:
// 只接把 regex 寫在裡面
newString = <String>.replace(/<p>/g, '<div class="paragraph">')
// 先建立 regex
let regex = new RegExp(wordToBeReplaced, 'gi')
let newString = <String>.replace(regex, 'wordToReplace')
/.../g
: global 的意思,找到之後會繼續往後配對
/.../i
: case insensitive 的意思
/* 找到第一個就不往後找 */
'banana'.replace(/na/, 'NA'); // 'baNAna'
/* 把 n 後面和後面的字元 */
'banana'.replace(/n./, 'NA'); // 'baNAna'
'banana'.replace(/na/g, 'NA'); // 'baNANA'
'banana'.replace(/na/gi, 'NA'); // 'baNANA'
搭配括號和 $n
var re = /(\w+)\s(\w+)/;
var str = 'John Smith';
var newStr = str.replace(re, '$2, $1');
console.log(newStr);
搭配 replacer function
function replacer(match, p1, p2, p3, offset, string) {
// p1 is non-digits, p2 digits, and p3 non-alphanumerics
return [p1, p2, p3].join(' - ');
}
var newString = 'abc12345#$*%'.replace(/([^\d]*)(\d*)([^\w]*)/, replacer);
console.log(newString); // abc - 12345 - #$*%
String.prototype.match:尋找並取出內容
String.prototype.match @ MDN
使用 String.prototype.match(regexp)
這個方法來判斷給的字串當中是否有符合該 regexp pattern 的內容,有的話以陣列回傳,沒有的話回傳 null
。
如果這個 regexp 的 pattern 不包含 g
標籤,那麼 str.match()
回傳的結果和 RegExp.exec()
是一樣的,在回傳的陣列中會包含:
input
屬性:原本被解析的字串index
屬性:第一個被找的字串的 index 值- 所有配對的結果
/* 不包含 g 的話,結果和 RegExp.exec() 一樣 */
let matchedResult = 'An apple a day, keeps apple away.'.match(/(a.)(p.)e/);
// [ 'apple', 'ap', 'pl', index: 3, input: 'An apple a day, keeps apple away.' ]
如果 pattern 中包含 g
的話,那麼回傳的陣列中會直接是整個被 matched 到的字:
/* 包含 g 的話,會直接回傳配對到的結果 */
let matchedResult = 'An apple a day, keeps apple away.'.match(/(a.)(p.)e/g);
// [ 'apple', 'apple' ]
若給入一個非 regexp 的物件,則會自動透過
new RegExp(obj)
轉換;若沒有代入任何參數的話,則會得到帶有空字串的陣列([""]
)。
使用範例
每個 ()
會變成一個 $
let matchedResult = 'An apple a day'.match(/(a.)(p.)e/);
RegExp.$1; // ap
RegExp.$2; // pl
'banana'.match(/(.)(a)/g); // [ 'ba', 'na', 'na' ]
// $1 = ['b', 'n', 'n']
// $2 = ['a', 'a', 'a']
// "/" 是特殊字元要用反斜線
'2017/05/16'.match(/(.*)\/(.*)\/(.*)/);
// ['2017/05/16', '2017', '05', '16']
'2017/05/16'.match(/.*\/.*\/.*/);
// [ '2017/05/16' ]
/**
* 擷取網址中的內容
**/
let url = 'https://www.ptt.cc/bbs/CodeJob/M.1513840968.A.F93.html'
let timestamp = url.match(/\/M\.(.+)\.A/)
console.log(timestamp[1]) // 1513840968
// result of timestamp
[
'/M.1513840968.A', // 該正規式會匹配到的內容
'1513840968', // 透過 match () 選取到的內容
index: 30, // 從哪個 index 開始批配到
input: 'https://www.ptt.cc/bbs/CodeJob/M.1513840968.A.F93.html' // 輸入的內容
]
搭配 filter 篩選結果
搭配 Array.prototype.filter
我們就可以根據使用者輸入的內容(wordToMatch)來從 cities 中篩選資料:
function findMatch(wordToMatch, cities) {
return cities.filter((place) => {
/**
* g: global search
* i: case insensitive search
**/
let regex = new RegExp(wordToMatch, 'gi');
return place.city.match(regex) || place.state.match(regex);
});
}
String.prototype.search():檢驗字串是否包含
var str = 'hey JudE';
var re = /[A-Z]/g;
var re2 = /[.]/g;
console.log(str.search(re)); // returns 4, which is the index of the first capital letter "J"
console.log(str.search(re2)); // returns -1 cannot find '.' dot punctuation
RegExp.prototype.test():檢驗字串是否包含
// 判斷是不是數值
/^[0-9]+$/.test(<testString>) // return True/False