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