前言
正則表達(dá)式是一種強(qiáng)大的模式匹配工具,可以用于在字符串中查找、替換和提取特定的文本。
分組是一項(xiàng)非常重要的功能,它允許我們將模式進(jìn)行分組,并在匹配過程中對(duì)分組進(jìn)行操作。除了基本的分組語(yǔ)法外,正則表達(dá)式還提供了前瞻和后顧這兩種高級(jí)分組技術(shù),它們能夠在匹配過程中對(duì)分組進(jìn)行更精確的控制。
前瞻和后顧是一種零寬度斷言,它們用于在匹配過程中指定一個(gè)位置,而不是實(shí)際匹配的內(nèi)容。前瞻和后顧可以幫助我們?cè)谄ヅ涮囟J綍r(shí),確保其前后滿足一定的條件。
本文將詳細(xì)介紹正則表達(dá)式中的分組,前瞻和后顧,通過簡(jiǎn)單清晰的JAVAScript示例,帶領(lǐng)大家徹底搞明白這幾個(gè)讓人難以理解的概念。
正則基礎(chǔ)
先來(lái)簡(jiǎn)單介紹一下正則表達(dá)式的基礎(chǔ)語(yǔ)法,如果你已經(jīng)是老手,基礎(chǔ)比較好,這些對(duì)你來(lái)說(shuō)肯定是小菜一碟,那么可以直接跳過這一部分~
正則表達(dá)式由一個(gè)模式和一些可選的修飾符組成。模式是由字符和特殊字符組成的字符串,它定義了我們要匹配的模式。特殊字符具有特殊的含義,例如元字符(如d、w、s等)表示特定的字符類別,字符類(如[abc])表示字符的集合,量詞(如*、+、?等)表示匹配次數(shù)等。
下面是一些常用的正則表達(dá)式元字符和字符類別:
-
d
:匹配任意一個(gè)數(shù)字。 -
w
:匹配任意一個(gè)字母、數(shù)字或下劃線。 -
s
:匹配任意一個(gè)空白字符(空格、制表符、換行符等)。 -
.
:匹配除換行符以外的任意一個(gè)字符。 -
[abc]
:匹配字符集合中的任意一個(gè)字符(a、b或c)。 -
[^abc]
:匹配除字符集合中的任意一個(gè)字符以外的字符。 -
b
:匹配單詞的邊界。
除了元字符和字符類別,我們還可以使用量詞來(lái)指定匹配次數(shù):
-
*
:匹配前面的元素零次或多次。 -
+
:匹配前面的元素一次或多次。 -
?
:匹配前面的元素零次或一次。 -
{n}
:匹配前面的元素恰好 n 次。 -
{n,}
:匹配前面的元素至少 n 次。 -
{n,m}
:匹配前面的元素至少 n 次,但不超過 m 次。
修飾符是可選的,用于指定匹配的方式。常見的修飾符包括:
-
g
:全局匹配,找到所有的匹配項(xiàng)而不僅僅是第一個(gè)。 -
i
:忽略大小寫,不區(qū)分大小寫地匹配。 -
m
:多行匹配,將^
和$
匹配行的開始和結(jié)束,而不僅僅是整個(gè)字符串的開始和結(jié)束。
在JavaScript中,我們可以使用正則表達(dá)式的方法來(lái)執(zhí)行各種操作。以下是一些常用的方法:
-
test()
:測(cè)試字符串是否匹配模式,返回布爾值。 -
exec()
:在字符串中執(zhí)行匹配,返回匹配結(jié)果的詳細(xì)信息。 -
match()
:在字符串中查找匹配,返回匹配結(jié)果的數(shù)組。 -
search()
:在字符串中搜索匹配,返回匹配的位置。 -
replace()
:替換字符串中的匹配項(xiàng)。 -
split()
:根據(jù)匹配項(xiàng)將字符串拆分為數(shù)組。
分組
分組可以將正則表達(dá)式中的一部分內(nèi)容視為一個(gè)整體,并對(duì)其進(jìn)行操作。通過使用括號(hào)將需要分組的內(nèi)容括起來(lái),我們可以創(chuàng)建一個(gè)分組。分組可以用于多種用途,包括匹配、替換和提取信息。
在匹配方面,分組可以幫助我們將匹配的內(nèi)容進(jìn)行分類。例如,我們可以使用分組來(lái)匹配一個(gè)特定的模式,并將匹配的結(jié)果保存在一個(gè)分組中。這樣,我們就可以更方便地提取出我們所需的信息。
在替換方面,分組可以幫助我們?cè)谔鎿Q過程中保留一部分內(nèi)容。通過使用分組,我們可以將匹配的內(nèi)容進(jìn)行捕獲,并在替換的過程中使用這些捕獲的內(nèi)容。這樣,我們可以實(shí)現(xiàn)更加復(fù)雜和靈活的替換操作。
在提取信息方面,分組可以幫助我們從文本中提取出我們感興趣的內(nèi)容。通過使用分組,我們可以將需要提取的內(nèi)容進(jìn)行捕獲,并將其保存在一個(gè)分組中。這樣,我們就可以輕松地獲取到我們所需的信息。
接下來(lái)通過部分示例的應(yīng)用,深入探討正則表達(dá)式中的分組,希望能夠幫助大家更好地理解和應(yīng)用這一功能。
1.基本分組語(yǔ)法
使用小括號(hào) ()
來(lái)創(chuàng)建一個(gè)分組。分組可以包含一個(gè)或多個(gè)字符,用于表示一個(gè)特定的模式。例如,(abc)
表示一個(gè)由字符 "abc" 組成的模式。
const str = "I love cats and dogs";
const pattern = /(love cats)/;
const result = str.match(pattern);
console.log(result[0]); // 輸出:"love cats"
console.log(result[1]); // 輸出:"love cats"
2.捕獲分組
它允許我們?cè)谄ヅ溥^程中獲取分組的值,并進(jìn)行后續(xù)的處理。捕獲組可以通過索引或命名來(lái)引用。
示例一:在一段字符串中取出其中的電子郵件地址
const str = "My emAIl address is john@example.com";
const pattern = /(w+@w+.w+)/;
const result = str.match(pattern);
console.log(result[0]); // 輸出:"john@example.com"
console.log(result[1]); // 輸出:"john@example.com"
在上述示例中,使用 (w+@w+.w+)
創(chuàng)建了一個(gè)分組,它匹配了電子郵件地址,并將其作為捕獲組返回。
示例二:在一段字符串中匹配并提取出其中的電話號(hào)碼
const str = "My phone number is (123) 456-7890";
const pattern = /((d{3}))s(d{3})-(d{4})/;
const result = str.match(pattern);
console.log(result[0]); // 輸出:"(123) 456-7890"
console.log(result[1]); // 輸出:"123"
console.log(result[2]); // 輸出:"456"
console.log(result[3]); // 輸出:"7890"
在上述示例中,使用 ((d{3}))s(d{3})-(d{4})
創(chuàng)建了三個(gè)分組,分別匹配了電話號(hào)碼的區(qū)號(hào)、前三位和后四位,并將它們作為捕獲組返回。
示例三:搭配replace使用
const str = "aaa,bbb,ccc";
str.replace(/(w+),(w+),(w+)/, "$3,$2,$1");//輸出'ccc,bbb,aaa'
-
$1代表第一個(gè)(w+)匹配到的內(nèi)容,即aaa
-
$2代表第一個(gè)(w+)匹配到的內(nèi)容,即bbb
-
$3代表第一個(gè)(w+)匹配到的內(nèi)容,即ccc
3.非捕獲分組
非捕獲分組是一種在正則表達(dá)式中使用的特殊語(yǔ)法,它允許我們創(chuàng)建一個(gè)分組(用括號(hào)包圍的部分),但并不捕獲該分組的結(jié)果。這意味著該分組將只用于改變匹配的行為,而不會(huì)影響返回的匹配結(jié)果。
非捕獲分組的語(yǔ)法是(?:pattern)
,其中,pattern
是我們要匹配的模式
示例一:
const regex = /(?:abc)/g;
在這個(gè)例子中,(?:abc)
是一個(gè)非捕獲分組。這意味著正則表達(dá)式會(huì)嘗試匹配 "abc",但不會(huì)將這個(gè)匹配結(jié)果保存下來(lái)。因此,當(dāng)我們使用 match()
或 search()
方法時(shí),返回的結(jié)果將不包含這個(gè)非捕獲分組的匹配結(jié)果。
然而,非捕獲分組仍然可以影響正則表達(dá)式的行為。例如,它們可以用于改變匹配的優(yōu)先級(jí),改變單詞邊界的行為,或者簡(jiǎn)單地創(chuàng)建一種不需要被捕獲的模式。
示例二:匹配域名
const str = "https://www.doorverse.com?v=123";
const regex = /(?:http|https)://(?:[a-z]+.)+(?:[a-z]+)/i;
const result = str.match(regex);
console.log(result[0]); // 輸出:"https://www.doorverse.com"
在這個(gè)例子中,正則表達(dá)式嘗試匹配以 "http://" 或 "https://" 開頭的 URL,但并不需要捕獲這些前綴。因此,這些前綴被放在了一個(gè)非捕獲分組中。同樣,這個(gè)正則表達(dá)式也試圖匹配一種形式的 URL,這個(gè) URL的前綴是一種由字母組成的子域名字(例如 "google."),后面跟著的是頂級(jí)域名(例如 "com")。這些都被放在了非捕獲分組中。這樣做可以讓正則表達(dá)式更加靈活,同時(shí)又不會(huì)影響到需要捕獲的 URL 部分。
4.反向引用分組
反向引用使用 數(shù)字
的形式,其中數(shù)字表示先前捕獲的分組的索引。當(dāng)使用反向引用時(shí),正則表達(dá)式引擎會(huì)嘗試匹配與先前捕獲的內(nèi)容相同的內(nèi)容。
示例一:匹配連續(xù)重復(fù)的字符
const str = "abab";
const pattern = /(w+)1/;
const result = str.match(pattern);
console.log(result[0]); // 輸出:"abab"
console.log(result[1]); // 輸出:"ab"
在上述示例中,使用 (w)1
創(chuàng)建了一個(gè)分組,并使用 1
后向引用來(lái)引用先前捕獲的字符,從而匹配連續(xù)重復(fù)的字符。
示例二:匹配類型為abab的數(shù)字
var str = 'ooo1212ooo2323ooo3434ooo1234';
var reg = /(d)(d)12/g;
var result = str.match(reg);
console.log(result); // ['1212', '2323', '3434']
在上述示例中,所定義的reg是, d匹配數(shù)字,1對(duì)應(yīng)的是第一個(gè)表達(dá)式(d),2對(duì)應(yīng)的是第二個(gè)表達(dá)式(d),g是全局匹配
前瞻
前瞻是指在匹配過程中,我們可以在當(dāng)前位置向前查看,以確定是否滿足某種條件。通過使用前瞻,我們可以對(duì)匹配的結(jié)果進(jìn)行更精確的控制,從而實(shí)現(xiàn)更復(fù)雜的匹配需求。
在正則表達(dá)式中,有兩種常見的前瞻:正向前瞻和負(fù)向前瞻。正向前瞻使用肯定的條件來(lái)匹配,即只有當(dāng)某個(gè)模式的后面緊跟著滿足指定條件的內(nèi)容時(shí),才認(rèn)為匹配成功。而負(fù)向前瞻則使用否定的條件來(lái)匹配,即只有當(dāng)某個(gè)模式的后面不滿足指定條件的內(nèi)容時(shí),才認(rèn)為匹配成功。
通過使用前瞻,我們可以實(shí)現(xiàn)一些復(fù)雜的匹配需求。例如,我們可以使用正向前瞻來(lái)匹配一個(gè)單詞后面跟著某個(gè)特定字符的情況,或者使用負(fù)向前瞻來(lái)匹配一個(gè)單詞后面不跟著某個(gè)特定字符的情況。這樣,我們就可以更加靈活地處理匹配的結(jié)果。
接下來(lái)我們將通過實(shí)際的例子和案例,幫助大家更好地理解和應(yīng)用前瞻。同時(shí),我們也將介紹一些常見的前瞻應(yīng)用場(chǎng)景,幫助大家更好地掌握正則表達(dá)式中的前瞻功能,提升文本處理的效率和準(zhǔn)確性。
1. 正向前瞻
正向前瞻的語(yǔ)法是使用括號(hào)和問號(hào)來(lái)表示,即(?=pattern)
,其中pattern
表示要查找的模式。當(dāng)正向前瞻被使用時(shí),它會(huì)在當(dāng)前位置向前查找,如果滿足指定的條件,則返回匹配成功,否則返回匹配失敗。
示例一:匹配郵箱地址中的用戶名
const emails = ['john@example.com', 'jane.doe@example.com', 'foo@bar.com'];
const usernameRegex = /w+(?=@)/;
emails.forEach(email => {
const match = email.match(usernameRegex);
console.log(match[0]);
});
運(yùn)行上述代碼,我們可以得到以下輸出:
john
jane.doe
foo
在這個(gè)例子中,我們使用了正向前瞻(?=@)
來(lái)匹配@符號(hào)之前的內(nèi)容。w+
表示匹配一個(gè)或多個(gè)字母、數(shù)字或下劃線,(?=@)
表示要求在當(dāng)前位置向前查找,必須緊跟著@符號(hào)。
示例二:匹配包含特定單詞的句子
假設(shè)我們有一段文本,我們想要匹配其中包含特定單詞的句子。
const text = 'I love JavaScript. JavaScript is amazing. Python/ target=_blank class=infotextkey>Python is also great.';
const word = 'JavaScript';
const sentenceRegex = /[^.?!]*(?=bJavaScriptb)[^.?!]*[.?!]/g;
const matches = text.match(sentenceRegex);
console.log(matches);
運(yùn)行上述代碼,我們可以得到以下輸出:
[ 'I love JavaScript.', ' JavaScript is amazing.' ]
在這個(gè)例子中,我們使用了正向前瞻(?=bJavaScriptb)
來(lái)匹配包含特定單詞JavaScript
的句子。[^.?!]*
表示匹配任意數(shù)量的非句子結(jié)束符(句號(hào)、問號(hào)、感嘆號(hào))的字符,bJavaScriptb
表示匹配單詞JavaScript
,[^.?!]*[.?!]
表示匹配任意數(shù)量的非句子結(jié)束符后跟一個(gè)句子結(jié)束符的字符。
示例三:匹配密碼強(qiáng)度
假設(shè)我們要驗(yàn)證用戶輸入的密碼強(qiáng)度,要求密碼必須包含至少一個(gè)大寫字母、一個(gè)小寫字母和一個(gè)數(shù)字。
const passwords = ['password123', 'Pass123', 'passWORD', '123456'];
const passwordRegex = /^(?=.*[a-z])(?=.*[A-Z])(?=.*d).{8,}$/;
passwords.forEach(password => {
const isValid = passwordRegex.test(password);
console.log(`${password}: ${isValid}`);
});
運(yùn)行上述代碼,我們可以得到以下輸出:
password123: false
Pass123: false
passWORD: false
123456: false
在這個(gè)例子中,我們使用了正向前瞻(?=.*[a-z])
、(?=.*[A-Z])
和(?=.*d)
來(lái)分別匹配至少一個(gè)小寫字母、一個(gè)大寫字母和一個(gè)數(shù)字。.{8,}
表示匹配至少8個(gè)字符。^
和$
分別表示匹配字符串的開頭和結(jié)尾,確保整個(gè)字符串都滿足要求。
2. 負(fù)向前瞻
負(fù)向前瞻的語(yǔ)法結(jié)構(gòu)是 (?!pattern)
,它表示在當(dāng)前位置向前查找,確保接下來(lái)的文本不匹配 pattern
。如果匹配成功,則當(dāng)前位置不會(huì)被視為匹配項(xiàng),繼續(xù)向后匹配。
示例一:匹配不以 "abc" 開頭的字符串
const regex = /^(?!abc).*/;
console.log(regex.test("def")); // true
console.log(regex.test("abcxyz")); // false
示例二:匹配不以特定字符結(jié)尾的字符串
const regex = /^(?!.*[x|y|z]$).*/;
console.log(regex.test("abc")); // true
console.log(regex.test("defx")); // false
示例三:匹配不包含特定字符的字符串
const regex = /^(?!.*[x|y|z]).*/;
console.log(regex.test("abc123")); // true
console.log(regex.test("abcx")); // false
后顧
后顧是指在匹配過程中,我們可以在當(dāng)前位置向后查看,以確定是否滿足某種條件。通過使用后顧,我們可以對(duì)匹配的結(jié)果進(jìn)行更精確的控制,從而實(shí)現(xiàn)更復(fù)雜的匹配需求。這個(gè)特性已經(jīng)在ECMAScript 2018(ES9)正式發(fā)布了。
在正則表達(dá)式中,有兩種常見的后顧:正向后顧和負(fù)向后顧。正向后顧使用肯定的條件來(lái)匹配,即只有當(dāng)某個(gè)模式的前面緊跟著滿足指定條件的內(nèi)容時(shí),才認(rèn)為匹配成功。而負(fù)向后顧則使用否定的條件來(lái)匹配,即只有當(dāng)某個(gè)模式的前面不滿足指定條件的內(nèi)容時(shí),才認(rèn)為匹配成功。
通過使用后顧,我們可以實(shí)現(xiàn)一些復(fù)雜的匹配需求。例如,我們可以使用正向后顧來(lái)匹配一個(gè)特定字符前面跟著滿足某種條件的內(nèi)容,或者使用負(fù)向后顧來(lái)匹配一個(gè)特定字符前面不滿足某種條件的內(nèi)容。這樣,我們就可以更加靈活地處理匹配的結(jié)果。
1. 正向后顧
正向后顧語(yǔ)法結(jié)構(gòu)是(?<=pattern)
,表示匹配位置前面的內(nèi)容必須滿足指定的模式。
示例一:匹配以數(shù)字開頭的單詞
const str = "The price of the product is $50. It is a good deal.";
const regex = /(?<=b)d+b/g;
const matches = str.match(regex);
console.log(matches); // 輸出: ["50"]
示例二:匹配以特定前綴開頭的URL
const str = "Visit our website at https://example.com to learn more.";
const regex = /(?<=https://)w+.w+/g;
const matches = str.match(regex);
console.log(matches); // 匹配了以 `https://` 開頭的URL 輸出: ["example.com"]
示例三:匹配某個(gè)位置之前的特定字符
const str = "I love coding, but I hate debugging.";
const regex = /(?<=loves)w+/g;
const matches = str.match(regex);
console.log(matches); //匹配了位于 `love` 后面的單詞 輸出: ["coding"]
2. 負(fù)向后顧
負(fù)向后顧語(yǔ)法結(jié)構(gòu)是(?<!pattern)
,表示匹配位置前面的內(nèi)容不能滿足指定的模式。
示例一
// 匹配不是以123開頭的abc
const regex = /(?<!123)abc/g;;
console.log(regex.test("abc123")); // true
console.log(regex.test("123abc")); // false
常用的正則表達(dá)式
數(shù)字校驗(yàn)相關(guān)
-
校驗(yàn)整數(shù):
/^-?d+$/
-
校驗(yàn)正整數(shù):
/^d+$/
-
校驗(yàn)負(fù)整數(shù):
/^-d+$/
-
n位的數(shù)字:
/^d{n}$/
-
m-n位的數(shù)字:
/^d{m,n}$/
-
校驗(yàn)浮點(diǎn)數(shù):
/^-?d+(.d+)?$/
-
校驗(yàn)正浮點(diǎn)數(shù):
/^d+(.d+)?$/
-
校驗(yàn)負(fù)浮點(diǎn)數(shù):
/^-d+(.d+)?$/
-
校驗(yàn)數(shù)字字符串:
/^d+$/
-
校驗(yàn)百分比(0-100之間的數(shù)字):
/^([1-9]d?|100)$/
字符校驗(yàn)相關(guān)
-
校驗(yàn)英文字母:
/^[a-zA-Z]+$/
-
校驗(yàn)大寫英文字母:
/^[A-Z]+$/
-
校驗(yàn)小寫英文字母:
/^[a-z]+$/
-
校驗(yàn)數(shù)字和英文字母組合:
/^[a-zA-Z0-9]+$/
-
校驗(yàn)數(shù)字、英文字母和下劃線組合:
/^w+$/
-
校驗(yàn)中文字符:
/^[u4e00-u9fa5]+$/
特殊需求
-
匹配手機(jī)號(hào)碼:
/^1[3456789]d{9}$/
-
匹配郵箱地址:
/^w+([-+.]w+)*@w+([-.]w+)*.w+([-.]w+)*$/
-
匹配URL地址:
/^(http|https)://[^s]+$
-
匹配身份證號(hào)碼(18位):
/^d{17}[dXx]$/
-
匹配日期(YYYY-MM-DD):
/^d{4}-d{2}-d{2}$/
-
匹配IP地址:
/^((25[0-5]|2[0-4]d|1d{2}|[1-9]d|[1-9]).){3}(25[0-5]|2[0-4]d|1d{2}|[1-9]d|[1-9])$/
-
匹配郵政編碼:
/^[1-9]d{5}$/
-
匹配整數(shù):
/^-?d+$/
-
匹配浮點(diǎn)數(shù):
/^-?d+(.d+)?$/
-
匹配英文單詞:
/^[a-zA-Z]+$/
-
匹配中文字符:
/^[u4e00-u9fa5]+$/
-
匹配用戶名(字母開頭,允許字母、數(shù)字、下劃線,長(zhǎng)度為6-16位):
/^[a-zA-Z]w{5,15}$/
-
匹配密碼(包含大小寫字母和數(shù)字,長(zhǎng)度為6-20位):
/^(?=.*[a-z])(?=.*[A-Z])(?=.*d)[a-zA-Zd]{6,20}$/
-
匹配html標(biāo)簽:
/</?[^>]+>/
-
匹配16進(jìn)制顏色值:
/^#([0-9a-fA-F]{6}|[0-9a-fA-F]{3})$/
-
匹配QQ號(hào)碼:
/^[1-9]d{4,10}$/
-
匹配微信號(hào)(以字母開頭,允許字母、數(shù)字、下劃線,長(zhǎng)度為6-20位):
/^[a-zA-Z]([-_a-zA-Z0-9]{5,19})+$/
-
匹配車牌號(hào)(普通車牌和新能源車牌):
/^(京|津|滬|渝|冀|豫|云|遼|黑|湘|皖|魯|新|蘇|浙|贛|鄂|桂|甘|晉|蒙|陜|吉|閩|貴|粵|青|藏|川|寧|瓊)([A-HJ-NP-Z]{1}(([0-9]{5}[DF])|([DF][A-HJ-NP-Z0-9][0-9]{4})))$/
-
匹配mac地址:
/^([0-9A-Fa-f]{2}[:-]){5}[0-9A-Fa-f]{2}$/
-
匹配中國(guó)大陸固定電話號(hào)碼:
/^0d{2,3}-d{7,8}$/
結(jié)語(yǔ)
通過本文的介紹,相信大家已經(jīng)對(duì)前瞻和后顧有了更深入的理解,并能夠在實(shí)際開發(fā)中靈活運(yùn)用。
在實(shí)際的文本處理中,分組、前瞻和后顧經(jīng)常被用于復(fù)雜的匹配和替換需求。合理地運(yùn)用這些功能,可以提高我們的工作效率和準(zhǔn)確性。同時(shí),我們也需要注意正則表達(dá)式的語(yǔ)法規(guī)則和一些常見的陷阱,以避免出現(xiàn)錯(cuò)誤的匹配結(jié)果。
特別是在使用后顧斷言時(shí),需要注意瀏覽器的兼容性,以確保代碼在各種環(huán)境下都能正常運(yùn)行。
希望本文能夠給大家?guī)?lái)幫助,正則表達(dá)式是一個(gè)強(qiáng)大的工具,掌握好的話,將為我們的文本處理工作帶來(lái)更多的便利和效益。
參考
-
MDN JavaScript正則表達(dá)式文檔:https://developer.mozilla.org/zh-CN/docs/Web/JavaScript/Guide/Regular_Expressions