W3Cschool
恭喜您成為首批注冊用戶
獲得88經(jīng)驗(yàn)值獎(jiǎng)勵(lì)
在本文中,我們將深入介紹與正則表達(dá)式配合使用的各種方法。
str.match(regexp)
方法在字符串 str
中查找 regexp
的匹配項(xiàng)。
它有 3 種模式:
如果 regexp
不帶有修飾符 g
,則它以數(shù)組的形式返回第一個(gè)匹配項(xiàng),其中包含捕獲組和屬性 index
(匹配項(xiàng)的位置)、input
(輸入字符串,等于 str
):
如果 regexp
帶有修飾符 g
,則它將返回一個(gè)包含所有匹配項(xiàng)的數(shù)組,但不包含捕獲組和其它詳細(xì)信息。
如果沒有匹配項(xiàng),則無論是否帶有修飾符 g
,都將返回 null
。
這是一個(gè)重要的細(xì)微差別。如果沒有匹配項(xiàng),我們得到的不是一個(gè)空數(shù)組,而是 null
。忘記這一點(diǎn)很容易出錯(cuò),例如:
如果我們希望結(jié)果是一個(gè)數(shù)組,我們可以這樣寫:
let result = str.match(regexp) || [];
最近新增的特性
這是一個(gè)最近添加到 JavaScript 的特性。 舊式瀏覽器可能需要 polyfills.
方法 str.matchAll(regexp)
是 str.match
的“更新、改進(jìn)”的變體。
它主要用來搜索所有組的所有匹配項(xiàng)。
與 match
相比有 3 個(gè)區(qū)別:
Array.from
? 將其轉(zhuǎn)換為一個(gè)常規(guī)數(shù)組。g
? 的 ?str.match
? 相同)。null
?。用法示例:
let str = '<h1>Hello, world!</h1>';
let regexp = /<(.*?)>/g;
let matchAll = str.matchAll(regexp);
alert(matchAll); // [object RegExp String Iterator],不是數(shù)組,而是一個(gè)可迭代對象
matchAll = Array.from(matchAll); // 現(xiàn)在是數(shù)組了
let firstMatch = matchAll[0];
alert( firstMatch[0] ); // <h1>
alert( firstMatch[1] ); // h1
alert( firstMatch.index ); // 0
alert( firstMatch.input ); // <h1>Hello, world!</h1>
如果我們用 for..of
來遍歷 matchAll
的匹配項(xiàng),那么我們就不需要 Array.from
了。
使用正則表達(dá)式(或子字符串)作為分隔符來分割字符串。
我們可以用 ?split
? 來分割字符串,像這樣:
alert('12-34-56'.split('-')) // 數(shù)組 ['12', '34', '56']
但同樣,我們也可以用正則表達(dá)式:
alert('12, 34, 56'.split(/,\s*/)) // 數(shù)組 ['12', '34', '56']
方法 str.search(regexp)
返回第一個(gè)匹配項(xiàng)的位置,如果沒找到,則返回 -1
:
let str = "A drop of ink may make a million think";
alert( str.search( /ink/i ) ); // 10(第一個(gè)匹配位置)
重要限制:search
僅查找第一個(gè)匹配項(xiàng)。
如果我們需要其他匹配項(xiàng)的位置,則應(yīng)使用其他方法,例如用 str.matchAll(regexp)
查找所有位置。
這是用于搜索和替換的通用方法,是最有用的方法之一。它是搜索和替換字符串的瑞士軍刀。
我們可以在不使用正則表達(dá)式的情況下使用它來搜索和替換子字符串:
// 用冒號替換連字符
alert('12-34-56'.replace("-", ":")) // 12:34-56
不過有一個(gè)陷阱。
當(dāng) replace
的第一個(gè)參數(shù)是字符串時(shí),它只替換第一個(gè)匹配項(xiàng)。
你可以在上面的示例中看到:只有第一個(gè) "-"
被替換為了 ":"
。
如要找到所有的連字符,我們不應(yīng)該用字符串 "-"
,而應(yīng)使用帶 g
修飾符的正則表達(dá)式 /-/g
:
// 將所有連字符都替換為冒號
alert( '12-34-56'.replace( /-/g, ":" ) ) // 12:34:56
第二個(gè)參數(shù)是替換字符串。我們可以在其中使用特殊字符:
符號 | 替換字符串中的行為 |
---|---|
$&
|
插入整個(gè)匹配項(xiàng) |
$`
|
插入字符串中匹配項(xiàng)之前的字符串部分 |
$'
|
插入字符串中匹配項(xiàng)之后的字符串部分 |
$n
|
如果 n 是一個(gè) 1-2 位的數(shù)字,則插入第 n 個(gè)分組的內(nèi)容,詳見 捕獲組
|
$<name>
|
插入帶有給定 name 的括號內(nèi)的內(nèi)容,詳見 捕獲組
|
$$
|
插入字符 $
|
例如:
let str = "John Smith";
// 交換名字和姓氏
alert(str.replace(/(john) (smith)/i, '$2, $1')) // Smith, John
對于需要“智能”替換的場景,第二個(gè)參數(shù)可以是一個(gè)函數(shù)。
每次匹配都會調(diào)用這個(gè)函數(shù),并且返回的值將作為替換字符串插入。
該函數(shù) func(match, p1, p2, ..., pn, offset, input, groups)
帶參數(shù)調(diào)用:
match
? —— 匹配項(xiàng),p1, p2, ..., pn
? —— 捕獲組的內(nèi)容(如有),offset
? —— 匹配項(xiàng)的位置,input
? —— 源字符串,groups
? —— 具有命名的捕獲組的對象。如果正則表達(dá)式中沒有括號,則只有 3 個(gè)參數(shù):func(str, offset, input)
。
例如,將所有匹配項(xiàng)都大寫:
let str = "html and css";
let result = str.replace(/html|css/gi, str => str.toUpperCase());
alert(result); // HTML and CSS
將每個(gè)匹配項(xiàng)替換為其在字符串中的位置:
alert("Ho-Ho-ho".replace(/ho/gi, (match, offset) => offset)); // 0-3-6
在下面的示例中,有兩對括號,因此將使用 5 個(gè)參數(shù)調(diào)用替換函數(shù):第一個(gè)是完全匹配項(xiàng),然后是 2 對括號,然后是(在示例中未使用)匹配位置和源字符串:
let str = "John Smith";
let result = str.replace(/(\w+) (\w+)/, (match, name, surname) => `${surname}, ${name}`);
alert(result); // Smith, John
如果有許多組,用 rest 參數(shù)(…)可以很方便的訪問:
let str = "John Smith";
let result = str.replace(/(\w+) (\w+)/, (...match) => `${match[2]}, ${match[1]}`);
alert(result); // Smith, John
或者,如果我們使用的是命名組,則帶有它們的 groups
對象始終是最后一個(gè)對象,所以我們可以像這樣獲取它:
let str = "John Smith";
let result = str.replace(/(?<name>\w+) (?<surname>\w+)/, (...match) => {
let groups = match.pop();
return `${groups.surname}, ${groups.name}`;
});
alert(result); // Smith, John
使用函數(shù)可以為我們提供終極替換功能,因?yàn)樗梢垣@取匹配項(xiàng)的所有信息,可以訪問外部變量,可以做任何事。
這個(gè)方法與 str.replace
本質(zhì)上是一樣的,但有兩個(gè)主要的區(qū)別:
replace
只會替換 第一個(gè)。g
的正則表達(dá)式,則會報(bào)錯(cuò)。帶有修飾符 g
,它的工作方式與 replace
相同。 replaceAll
的主要用途是替換所有出現(xiàn)的字符串。
像這樣:
// 使用冒號替換所有破折號
alert('12-34-56'.replaceAll("-", ":")) // 12:34:56
regexp.exec(str)
方法返回字符串 str
中的 regexp
匹配項(xiàng)。與以前的方法不同,它是在正則表達(dá)式而不是在字符串上調(diào)用的。
它的行為取決于正則表達(dá)式是否具有修飾符 g
。
如果沒有修飾符 g
,則 regexp.exec(str)
會返回與 第一個(gè)匹配項(xiàng),就像 str.match(regexp)
那樣。這種行為并沒有帶來任何新的東西。
但是,如果有修飾符 g
,那么:
regexp.exec(str)
會返回第一個(gè)匹配項(xiàng),并將緊隨其后的位置保存在屬性 regexp.lastIndex
中。regexp.lastIndex
開始搜索,返回下一個(gè)匹配項(xiàng),并將其后的位置保存在 regexp.lastIndex
中。regexp.exec
返回 null
,并將 regexp.lastIndex
重置為 0
。因此,重復(fù)調(diào)用會一個(gè)接一個(gè)地返回所有匹配項(xiàng),使用屬性 regexp.lastIndex
來跟蹤當(dāng)前搜索位置。
過去,在將 str.matchAll
方法添加到 JavaScript 之前,會在循環(huán)中調(diào)用 regexp.exec
來獲取組的所有匹配項(xiàng):
let str = 'More about JavaScript at https://javascript.info';
let regexp = /javascript/ig;
let result;
while (result = regexp.exec(str)) {
alert( `Found ${result[0]} at position ${result.index}` );
// 在位置 11 找到了 JavaScript,然后
// 在位置 33 找到了 javascript
}
這現(xiàn)在也有效,盡管對于較新的瀏覽器 str.matchAll
通常更方便。
我們可以通過手動(dòng)設(shè)置 lastIndex
,用 regexp.exec
從給定位置進(jìn)行搜索。
例如:
let str = 'Hello, world!';
let regexp = /\w+/g; // 沒有修飾符 "g",lastIndex 屬性會被忽略
regexp.lastIndex = 5; // 從第 5 個(gè)位置搜索(從逗號開始)
alert( regexp.exec(str) ); // world
如果正則表達(dá)式帶有修飾符 y
,則搜索將精確地在 regexp.lastIndex
位置執(zhí)行,不會再進(jìn)一步。
讓我們將上面示例中的 g
修飾符替換為 y
。現(xiàn)在沒有找到匹配項(xiàng),因?yàn)樵谖恢?nbsp;5
處沒有單詞:
let str = 'Hello, world!';
let regexp = /\w+/y;
regexp.lastIndex = 5; // 在位置 5 精確查找
alert( regexp.exec(str) ); // null
當(dāng)我們需要通過正則表達(dá)式在確切位置而不是其后的某處從字符串中“讀取”某些內(nèi)容時(shí),這很方便。
方法 regexp.test(str)
查找匹配項(xiàng),然后返回 true/false
表示是否存在。
例如:
let str = "I love JavaScript";
// 這兩個(gè)測試相同
alert( /love/i.test(str) ); // true
alert( str.search(/love/i) != -1 ); // true
一個(gè)否定答案的例子:
let str = "Bla-bla-bla";
alert( /love/i.test(str) ); // false
alert( str.search(/love/i) != -1 ); // false
如果正則表達(dá)式帶有修飾符 g
,則 regexp.test
從 regexp.lastIndex
屬性開始查找并更新此屬性,就像 regexp.exec
一樣。
因此,我們可以用它從給定位置進(jìn)行查找:
let regexp = /love/gi;
let str = "I love JavaScript";
// 從位置 10 開始搜索:
regexp.lastIndex = 10;
alert( regexp.test(str) ); // false(沒有匹配項(xiàng))
相同的全局正則表達(dá)式在不同的源字符串上測試可能會失敗
如果我們在不同的源字符串上應(yīng)用相同的全局正則表達(dá)式,可能會出現(xiàn)錯(cuò)誤的結(jié)果,因?yàn)?nbsp;
regexp.test
的調(diào)用會增加regexp.lastIndex
屬性值,因此在另一個(gè)字符串中的搜索可能是從非 0 位置開始的。
例如,這里我們在同一文本上調(diào)用
regexp.test
兩次,而第二次調(diào)用失敗了:
let regexp = /javascript/g; // (新建立的 regexp:regexp.lastIndex=0) alert( regexp.test("javascript") ); // true(現(xiàn)在 regexp.lastIndex=10) alert( regexp.test("javascript") ); // false
這正是因?yàn)樵诘诙€(gè)測試中
regexp.lastIndex
不為零。
如要解決這個(gè)問題,我們可以在每次搜索之前設(shè)置
regexp.lastIndex = 0
。或者,不要在正則表達(dá)式上調(diào)用方法,而是使用字符串方法str.match/search/...
,這些方法不使用lastIndex
。
Copyright©2021 w3cschool編程獅|閩ICP備15016281號-3|閩公網(wǎng)安備35020302033924號
違法和不良信息舉報(bào)電話:173-0602-2364|舉報(bào)郵箱:jubao@eeedong.com
掃描二維碼
下載編程獅App
編程獅公眾號
聯(lián)系方式:
更多建議: