正则表达式(下) && 字符串.match方法检查正则表达式中的子字符串是否存在于原字符串,并返回存在的子字符串 && 字符串.replace()方法
正则表达式的test只能检查字符串是否存在,返回true或false,而字符串的match检查是否存在时会返回子字符串。
"Hello, World!".match(/Hello/); let ourStr = "Regular expressions"; let ourRegex = /expressions/; ourStr.match(ourRegex);
第一个match返回["Hello"],第二个match返回
["expressions"]。.match语法与之前使用的.test方法“相反”:
'string'.match(/regex/); /regex/.test('string');
再看一个例子:
let extractStr = "Extract the word 'coding' from this string."; let codingRegex = /coding/; let result = extractStr.match(codingRegex); //注意这儿是'字符串.match'而不是'正则表达式.' console.log(result); /*控制台输出: [ 'coding', index: 18, input: 'Extract the word \'coding\' from this string.', groups: undefined ]*/
如果子字符串在原字符串中多次出现,按上面的办法也只会给出一次:
let testStr = "Repeat, Repeat, Repeat"; let ourRegex = /Repeat/; let myResult=testStr.match(ourRegex); console.log(myResult); /*控制台输出: ['Repeat', index: 0, input: 'Repeat, Repeat, Repeat', groups: undefined ]*/
要多次搜索并提取文本形式的话,则要使用全局搜索标志(flag):g。看下面例子:
let testStr = "Repeat, Repeat, Repeat"; let ourRegex = /Repeat/g; let myResult=testStr.match(ourRegex); console.log(myResult); //[ 'Repeat', 'Repeat', 'Repeat' ]
看,这样就会全部提取出来。
let twinkleStar = "Twinkle, twinkle, little star"; let starRegex = /Twinkle/ig; //在正则表达式后可以有多个不同的flag(标志);i表示不区分大小写,g表示可多次搜索或提取(全局搜索);不区分前后顺序。 let result = twinkleStar.match(starRegex); console.log(result);//[ 'Twinkle', 'twinkle' ]
看,不论大小写、无论几个全部都提取出来了。
除了极端的匹配情况(完全匹配某模式、通配符' . '匹配任何单个字符),正则表达式还有适用于其他情况的形式。
例如,我们想要匹配bag、
big
、和bug
但不匹配 bog,这时可以通过创建正则表达式 /b[aiu]g/ 来实现。[aiu]是仅匹配字符a、i或u的字符类(character class),记得要用中括号括住:
let bigStr = "big";
let bagStr = "bag";
let bugStr = "bug";
let bogStr = "bog";
let bgRegex = /b[aiu]g/;
console.log(bigStr.match(bgRegex)); //[ 'big', index: 0, input: 'big', groups: undefined ]
console.log(bagStr.match(bgRegex)); //[ 'bag', index: 0, input: 'bag', groups: undefined ]
console.log(bugStr.match(bgRegex)); //[ 'bug', index: 0, input: 'bug', groups: undefined ]
console.log(bogStr.match(bgRegex)); //null
看另一个例子。在正则表达式中使用带有元音(a、e、i、o、u)的字符类来查找字符串QuotesSample中的所有元音,不区分大小写:

let quoteSample = "Beware of bugs in the above code; I have only proved it correct, not tried it."; let vowelRegex = /[aeiou]/ig; // let result =quoteSample.match(vowelRegex); // console.log(result); /*控制台输出的结果: [ 'e', 'a', 'e', 'o', 'u', 'i', 'e', 'a', 'o', 'e', 'o', 'e', 'I', 'a', 'e', 'o', 'o', 'e', 'i', 'o', 'e', 'o', 'i', 'e', 'i' ] */
还有一种情况,当我们需要匹配大范围的字符(例如,字母表中的每个字母)时,就需要大量输入,这很麻烦。所幸有一个内置的特性可以运用。
在字符集内,我们可以使用连字符( - )定义要匹配的字符范围。例如,要匹配小写字母a到e,可以使用[a-e]:
let catStr = "cat";
let batStr = "bat";
let matStr = "mat";
let bgRegex = /[a-e]at/;
catStr.match(bgRegex);
batStr.match(bgRegex);
matStr.match(bgRegex);
上面三个match调用语句将依次返回值[“cat”]、[“bat”]和null。
看另一个例子。要求匹配字符串QuotesSample中的所有字母,不区分大小写:

let quoteSample = "The quick brown fox jumps over the lazy dog."; let alphabetRegex = /[a-z]/ig; let result =quoteSample.match(alphabetRegex) ; console.log(result); /*控制台输出如下: [ 'T', 'h', 'e', 'q', 'u', 'i', 'c', 'k', 'b', 'r', 'o', 'w', 'n', 'f', 'o', 'x', 'j', 'u', 'm', 'p', 's', 'o', 'v', 'e', 'r', 't', 'h', 'e', 'l', 'a', 'z', 'y', 'd', 'o', 'g' ] */
连字符(-)匹配字符范围不限于字母,它还可以匹配一系列数字。我们可以在单个字符集(记得字符集要用中括号括住)中组合一系列字母和数字:
let jennyStr = "Jenny8675309"; let myRegex1 = /[a-z0-9]/ig; let kk=jennyStr.match(myRegex1); console.log(kk);//[ 'J', 'e', 'n', 'n', 'y', '8', '6', '7', '5', '3', '0', '9' ]
再看一个例子:

let quoteSample = "Blueberry 3.141592653s are delicious."; let myRegex = /[h-s2-6]/ig; //记得要用中括号括住!i不区分大小写,g全局搜索。 let result =quoteSample.match(myRegex); console.log(result); /*控制台输出如下: [ 'l', 'r', 'r', '3', '4', '5', '2', '6', '5', '3', 's', 'r', 'l', 'i', 'i', 'o', 's' ] */
也可以创建一组不想匹配的字符,这种类型的字符集称为否定字符集。创建否定字符集的方法是在字符集里加插入符(尖括号):( ^ )。例如 /[^aeiou]/gi 表示匹配所有不是元音的字符。注意,像( . )、( ! )、 ( [ )、( @ )、( / )、空格都会被匹配,只要不是元音字母就会被匹配。看个例子:
let quoteSample = "3 blind mice."; let myRegex = /[^aeiou^0-9]/gi; //匹配非元音、非数字的字符。 let result = quoteSample.match(myRegex); console.log(result); //[ ' ', 'b', 'l', 'n', 'd', ' ', 'm', 'c', '.' ]
PS:当插入符不是放在字符集里,而是放在字符集外,插入符就起到搜索字符串开头文字(模式)的作用。看例子:
//例一: let rickyAndCal = "Cal and Ricky both like racing."; let calRegex = /^Cal/; //这里的^并不是置于字符集内!故不是取否之意! let result = calRegex.test(rickyAndCal); console.log(result); //true 由于字符串开头正是Cal,故返回true。 //例二: let rickyAndCal = "Ricky and Cal both like racing."; let calRegex = /^Cal/; //这里的^并不是置于字符集内!故不是取否之意! let result = calRegex.test(rickyAndCal); console.log(result); //false 由于字符串开头不是Cal,故返回false。
PPS:想要搜索字符串结尾文字(模式)的符号为美元符号$,看个例子:
let theEnding = "This is a never ending story"; let storyRegex = /story$/; storyRegex.test(theEnding); //true let noEnding = "Sometimes a story will have to end"; storyRegex.test(noEnding); //false
当想要匹配至少出现一次或连续重复出现的字符(或一组字符)时,可以使用加号(+)检查是否如此。
例如,/a+/g将在abc中找到一个匹配项并返回[“a”];将在aabc中找到单个匹配项并返回[“aa”];将在abab中找到两个匹配项并返回[“a”,“a”],因为两个a之间有b隔开了,不连续;在bcd中没有a,因此它无法找到匹配项。看个具体例子:
let difficultSpelling = "Mississsipspi"; let myRegex = /s+/g; //注意因为不是匹配字符集,故这儿不用加[]。 let result = difficultSpelling.match(myRegex); console.log(result); //[ 'ss', 'sss', 's' ]
再看一个例子:
let reCriminals = /C+/; // 此处用/C+[A-Z]*?/、/C+[a-z]*?/也能达到同样的效果。 /*经测试,测试用的字符串匹配此正则表达式返回情况如下: P1P5P4CCCcP2P6P3返回CCC C返回C CC返回CC P6P2P7P4P5CCCCCP3P1返回CCCCC ""返回null P1P2P3返回null P2P1P5P4CCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCP3返回CCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCC */
当想要匹配出现零次或多次的字符时,可以使用星号:*。
let soccerWord = "gooooooooal!"; let gPhrase = "gut feeling"; let oPhrase = "over the moon"; let goRegex = /go*/; soccerWord.match(goRegex); gPhrase.match(goRegex); oPhrase.match(goRegex);
按照顺序,三个match调用将返回值[“goooooooo”]、[“g”]和null。
默认情况下,正则表达式是贪婪的。例如,对于字符串“titanic”,匹配正则表达式 /t[a-z]*i/ 将返回[“titani”],它可以找到适合该模式的最大子字符串。我们可以使用'?'字符将正则表达式更改为惰性匹配。“titanic”匹配正则表达式 /t[a-z]*?i/ 则会返回["ti"]。(注:应避免用正则表达式解析HTML,但用正则表达式匹配HTML字符串的模式完全可以)看个例子:
要求返回HTML的<h1>标签:
let text = "<h1>Winter is coming</h1>"; let myRegex = /<h*?1>/; // 这里不能将*改为.,不能将*?去掉,也不能单独把*或?去掉。 let result = text.match(myRegex); console.log(result); //['<h1>']
JavaScript中与字母表最匹配的字符类是 \w(w为小写)。此快捷方式等于字符集[A-Za-z0-9_ ]。这个字符类匹配大小写字母、数字和下划线字符(_)。即
let longHand = /[A-Za-z0-9_]+/; 与 let shortHand = /\w+/;是相等的。看个例子:要求使用速记字符类\w计算字符串中的字母、数字、下划线总数:
let quoteSample = "The five .1_1"; let alphabetRegexV2 = /\w/g; //g为字符串内全局搜索标志 let result = quoteSample.match(alphabetRegexV2).length; console.log(result); //10
当要匹配与\w相反的模式(除字母、数字以外的所有内容,即匹配所有标点符号和空格)时,使用字符类 \W(w为大写)。此快捷方式等于字符集[^A-Za-z0-9_ ]。
看下面例子:
//例一: let shortHand = /\W/; let numbers = "42%"; let sentence = "Coding!"; numbers.match(shortHand); //["%"] sentence.match(shortHand); //["!"] //例二: let quoteSample = "The five boxing wizards jump quickly."; let nonAlphabetRegex = /\W/g; // let result = quoteSample.match(nonAlphabetRegex).length; console.log(result); //6(即5个空格符1个句点符)
当要查找所有数字时,快捷方式是 \d(d为小写)。这等于字符类[0-9],它查找0到9之间任何数字的单个字符。看个例子:使用速记字符类\d计算字符串中数字的位数:
let movieName = "2001: A Space Odyssey"; let numRegex = /\d/g; //g表示对整个字符串进行搜索。 let result = movieName.match(numRegex).length; console.log(result); //4
当要查找所有非数字字符时,快捷方式是 \D(d为大写)。这等于字符类[^0-9],它查找不是0到9之间任何数字的单个字符。看个例子:
let movieName = "2001: A Space."; let noNumRegex = /\D/g; //非数字字符包括空格、标点符号、大小写字母 let result = movieName.match(noNumRegex).length; console.log(result); //10
下面看一个小小的综合应用:
假设要对用户名进行检查:
用户名只能使用字母数字字符;用户名中的唯一数字必须在末尾,最后可以有零个或多个,用户名不能以数字开头;用户名字母可以是小写和大写;用户名必须至少有两个字符长,两个字符的用户名只能使用字母作为字符。
let username = "JackOfAllTrades"; let userCheck = /^[a-z][a-z]+\d*$|^[a-z]\d\d+$/i; //|是或者的意思 //使用这个/^[a-z]([0-9]{2,}|[a-z]+\d*)$/i也是可以的。 let result = userCheck.test(username); console.log(result);//true
使用\s(小写s)不仅可以匹配空格,还匹配回车符、制表符、换页符和换行符,可以将其视为类似于字符类 [ \r\t\f\n\v]。看例子:
let sample = " Whitespace is important in separating words"; let countWhiteSpace = /\s/g; let result = sample.match(countWhiteSpace); console.log(result); //[' ', ' ', ' ', ' ', ' ', ' ', ' '] 开头的制表符tab会返回2个单独的空格。
使用\S(大写S)可以搜索除空白之外的所有内容,同时也不匹配回车符、制表符、换页符和换行符,类似于字符类[^ \r\t\f\n\v]。看例子:
let sample = "Whitespace is "; let countNonWhiteSpace = /\S/g; let result = sample.match(countNonWhiteSpace); console.log(result); //[ 'W', 'h', 'i', 't', 'e', 's', 'p', 'a', 'c', 'e', 'i', 's' ]
使用花括号{ }可以匹配一定范围的模式。例如,要只匹配字符串ah中出现3到5次的字母a,正则表达式应该是 /a{3,5}h/ 。看例子——要求只在当有3到6个字母h时,才能匹配上整个字符串"Ohhh no":
let ohStr = "Ohhh no"; let ohRegex = /oh{3,6} no/i; //正则表达式是区分大小写的!若没加i,结果就是false。还有空格也要按原式写上。 let result = ohRegex.test(ohStr); console.log(result); //true
当花括号只写前面一个数字,后跟一个逗号时,表示至少要有这个数才能匹配。不需要设置上限。看例子:
let A4 = "haaaah"; let A2 = "haah"; let A100 = "h" + "a".repeat(100) + "h"; let multipleA = /ha{3,}h/; multipleA.test(A4); //true multipleA.test(A2); //false multipleA.test(A100); //true
当花括号里只有一个数字时,表示只有此特定数量的才能匹配上。看例子:
let A4 = "haaaah"; let A3 = "haaah"; let A100 = "h" + "a".repeat(100) + "h"; let multipleHA = /ha{3}h/; multipleHA.test(A4); //false multipleHA.test(A3); //true multipleHA.test(A100); //false
' ? '可以检查前面的元素是否为零或一个。即?前面的元素可有可无,有无都会匹配上。看个例子:
let american = "color"; let british = "colour"; let rainbowRegex= /colou?r/; rainbowRegex.test(american); //true rainbowRegex.test(british); //true
' (?=...) '表示正面预测检查,(希望...元素在)若存在元素...,则匹配时返回模式的其余部分。否则返回null。
' (?!...) '表示负面预测检查,(不希望...元素在)若不存在元素...,则匹配时返回模式的其余部分。否则返回null。
看例子:
例一:
let quit = "qu"; let noquit = "qt"; let quRegex= /q(?=u)/;//(希望u元素在)若存在u,则匹配时返回模式的其余部分。 let quRegex1= /q(?!u)/;//若不存在u,则匹配时返回模式的其余部分。否则返回null。 let qRegex = /q(?!u)/;//(不希望u元素在)若不存在u,则匹配时返回模式的其余部分。 let qRegex1 = /q(?=u)/;//若存在u,则匹配时返回模式的其余部分。否则返回null。 console.log(quit.match(quRegex)); //["q"] console.log(quit.match(quRegex1)); //null console.log(noquit.match(qRegex)); //["q"] console.log(noquit.match(qRegex1)); //null
例二:
let sampleWord = "astronaut"; let pwRegex = /(?=\w{6,})(?=\D+\d+\d+)/; //长度大于5个字符且具有两个连续数字的字符串才能匹配上。 //也可以用/(?=\w{6})(?=\w*\d{2})/ 达到同样效果。 let result = pwRegex.test(sampleWord); console.log(result); //false
小括号' ( ) '可以检查多组字符。比如,要检查Penguin或Pumpkin是否在字符串中,就可以用 /P(engu|umpk)in/g 作为正则表达式,然后用正则表达式的test方法检查所需的字符组是否在字符串中。看例子:
//例一: let testStr = "Pumpkin"; let testRegex = /P(engu|umpk)in/; testRegex.test(testStr); //true //例二: let myString = "Eleanor Roosevelt"; let myRegex = /(Franklin|Eleanor)\D* Roosevelt/; //区分大小写、检查是否包含Franklin Roosevelt 或 Eleanor Roosevelt、对中间名不做要求。 let result =myRegex.test(myString) ; console.log(result); //true
若不知道具体哪个词重复了,捕获组(Capture groups)可用于查找重复的子字符串。捕获组是通过将要捕获的正则表达式模式括在括号中来构造的。例如,要捕获由字母数字字符组成的单词,\w+将被括在括号内:/(\w+)/形成捕获组,捕获组匹配的子字符串保存到一个临时“变量”中,可以使用反斜杠和捕获组的编号(如\1)在同一正则表达式中访问该变量。捕获组会根据其左括号的位置(从左到右)自动编号,从1开始。例如,第一个左括号编号是1,第二个左括号编号就是2了。看例子:
let repeatNum = "42 42 42"; let reRegex = /^(\d+)(\s)\1\2\1$/; // 用/^(\d+) \1 \1$/也可以,或用/^(\d+)\s\1\s\1$/也可以,空格以\s代替。^搜索字符串开头文字,\s搜索空格,\1表示捕获组中对应变量的位置,$搜索字符串结尾文字。 let result = reRegex.test(repeatNum); let result1 =repeatNum.match(reRegex); console.log(result); //true console.log(result1); //['42 42 42','42']
当我们在字符串上使用.replace()方法搜索和替换字符串中的文本时,捕获组可以作为字符串.replace()方法的参数,起到搜索和替换的作用。
先看replace方法,它有两个参数,第一个参数是要搜索的正则表达式,第二个参数是用于替换匹配项的字符串或用于执行某些操作的函数。
看例子:
let wrongText = "The sky is silver."; let silverRegex = /silver/; wrongText.replace(silverRegex, "blue"); //返回字符串“The sky is blue.”
使用美元符号($)可以访问第一个参数中的捕获组:
"Code Camp".replace(/(\w+)\s(\w+)/, '$2 $1'); //返回字符串“Camp Code”
再看两个例子:
一、要求将字符串"one two three"倒置为"three two one":
let str = "one two three"; let fixRegex = /(\w+)\s(\w+)\s(\w+)/; //一定要加上加号+,表示至少匹配1个字符,否则不会占据位置。 let replaceText = "$3 $2 $1"; //使用捕获组的默认编号,让顺序倒置。 let result = str.replace(fixRegex, replaceText);//replace会返回替代后的字符串。 console.log(result); //three two one
二、要求将字符串的开头和结尾的空格去掉:
let hello = " Hello, World! "; let wsRegex = /^\s+ | \s+$/g; //\s表示空格,^符号取开头的\s,$符号取结尾的\s,g表示对整个字符串进行搜索。 let result = hello.replace(wsRegex,''); //以空字符""代替空格。 console.log(result); //Hello, World!
。。。