正则这部分习题不算多,但是我还是被卡住了挺久的,比预计要用的番茄时间多了好几个,主要是有几个之前没有弄懂的地方耽误了时间,加上习题pass需要完全满足检验指定的方法,否则在编辑器里测试没问题,但是test还是一直过不了。
旧版的正则只讲了最基础的内容,如\s, \d, [a-z]等基本语法,总共只有4、5道习题,新版内容添加了很多难度更高的知识,覆盖的范围更大。另外我把之前在其他地方学过的正则的内容一并总结过来,当做一次复习。
正则表达式
正则表达方法
- 习题里只用了正则表达式的字面量表达方法,用斜杠来表示**
/pattern/flags
** ,如const regex = /ab+c/;
- 还有一种方法是调用
RegExp
对象的构造函数**new RegExp(pattern, [, flags])
**其中,flags根据实际情况添加,如const regex = new RegExp("ab+c");
- 习题里只用了正则表达式的字面量表达方法,用斜杠来表示**
正则验证,**
.test
和.match
**方法的区别.test
的用法是**正则表达式.test(测试字符串)
**,返回一个布尔值结果,表明字符串能够通过正则表达式的测试.match
的用法是**测试字符串.match(正则表达式)
**,如果测试字符串无法满足正则表达式的格式,则返回null
,如果测试字符串满足正则表达式,则返回一个数组.test
方法是正则表达式的方法,RegExp.prototype.test()
.match
方法是字符串的方法,String.prototype.match()
两个方法挺像的,有时候容易搞混,我会把它们的原型记成是英语里的主语,谁去做什么事
.test
方法是正则
去测试其他的内容(字符串)是否能够通过它的测试(test),结果是是(true)或否(false).match
方法是字符串
去检查其他内容(正则)是否符合(match)它的格式,结果是字符串的某个部分符合(数组[0])
除了习题中用到的两个方法之外,正则表达式的相关方法还有:
RegExp
的exec
方法,用法和test
方法基本一样,RegExp.exec(str)
,区别在于返回结果是一个数组,它的返回结果和match
方法是一样的- 字符串除了
match
方法检验字符串是否匹配正则的规则之外,还可以- 使用
.replace
方法来替换掉符合正则规则的部分 - 使用
.split
方法,利用正则来指定切分字符串的规则 - 使用
.search
方法来搜索字符串是否匹配正则的规则,如果符合,就返回首次匹配项的所有,如果不符合,则返回-1
- 使用
正则的flags,即匹配模式,常见匹配模式有:
- **
g
**,即全局匹配,返回的结果包括所有匹配规则的字符串,如果非全局匹配,则只返回首次匹配项 - **
i
**,即大小写不敏感匹配,在匹配时忽略大小写差异 - **
m
**,即多行匹配,使用多行匹配时,^
和$
作为首行和末行标志,而非首尾字符标志
- **
匹配字符串
- 常规字符串**
abc
** - wildcard字符**
.
**,用一个点表示,可以指代任意字符(不可指代新行newline),类似于麻将里的癞子,查了一下wildcard这个词,既可指纸牌游戏里的“变牌”,也可以只计算机里的通配符 - 选择性匹配 **
a|b|c
,也可以表示成[abc]
**,表示a或b或c都可以匹配 - 区间性匹配**
[a-z]
,[0-9]
,分别表示a-z的所有字母,0-9的所有数字,也可以组合使用,如[A-Za-z0-9]
**表示所有的字母和数字 - 反向匹配**
[^abc]
**,表示匹配不是a,b,c的字符
- 常规字符串**
匹配次数
*
字符出现0到多次+
字符出现1到多次?
字符出现0到1次{n, m}
字符出现最少n次,最多m次,其中,上下限都可以留空,如**{n,}
** 表示最少出现n次,最多不限次数,也可以只有一个数字,如**{n}
**,表示正好出现n次
位置匹配
/^ /
,^
符号在[]
方括号内表示非某一字符,在方括号外表示以某一字符开头,如**/^ab/
**表示以ab开头- **
/ $/
表示以某一字符结尾,如/ab$/
**表示以ab结尾
简写
\w
,等同于[A-Za-z0-9]
,表示所有的字母及数字- **
\W
等同于[^A-Za-z0-9]
**,表示所有非字母及数字的字符 - **
\d
等同于[0-9]
**,表示所有数字 - **
\D
等同于[^0-9]
**,表示所有非数字 - **
\s
**表示空格 - **
\S
**表示非空格
断言
- 零宽正向先行断言,表达式为**
(?=pattern)
**,表示紧接该位置之后的字符能够匹配pattern,如"a regular expression".match(/re(?=gular)/)
匹配结果是regular中的re,但是不会匹配expression中的re;此外,零宽是指匹配的pattern不会占用字符,如"a regular expression".match(/re(?=gular)./)
匹配结果为reg,pattern本身没有消耗字符,只匹配位置 - 零宽负向先行断言,表达式为**
(?!pattern)
**,表示紧接该位置之后不能匹配patter,如"a regular expression".match(/re(?!gular)/)
匹配结果是expression中的re,不会匹配regular中的re - 零宽正向后行断言,表达式为**
(?<=pattern)
**,表示紧接该位置之前的字符能够匹配patter,如"a regular expression",match(/(?<=\w+)re/)
匹配结果是expression中的re,即re之前还有其他字符,无法匹配单词开头的re - 零宽负向后行断言,表达式为**
(?<!pattern)
**,表示紧接该位置之前的字符不能匹配pattern,如"a regular expression".match(/(?<!\w+)re/)
匹配结果是regular中的re,即不满足re之前有其他字符
- 零宽正向先行断言,表达式为**
匹配范围
- 正常情况下,字符串匹配正则的规则会返回满足规则的最长字符串,这叫做greedy matching(贪婪匹配),如
'titanic'.match(/t.*i/)
返回'titani'
- lazy matching(惰性匹配)可以匹配符合规则的最短字符串,使用方法是*在正则表达式中,在需要惰性匹配的部分(即可长可短的部分)后面添加
?
*,如'titanic'.match(/t.*?i/)
返回ti
- 正常情况下,字符串匹配正则的规则会返回满足规则的最长字符串,这叫做greedy matching(贪婪匹配),如
捕获组
对于需要重复使用的正则规则可以使用
()
来进行分组每个分组都会自动匹配一个组号,即从左到右,从1开始,依次累加,需要再次使用分组内的规则时,用
\组号
就可引用了如Reuse Patterns Using Capture Groups这道习题,正则需要表示数字重复恰好3次,中间由空格隔开,数字可以表示为
\d+
作为第一个分组,空格\s
可以作为第二个分组,一个数字出现三次的表达方式可以是/(/d+)\1\1/
,中间用逗号隔开可以这样表示/(\d+)(\s)\1\2\1/
,同时需要保证恰好3次,即前后都不会再出现数字,否则无法通过测试,那么/^(\d+)(\s)\1\2\1$/
分别将开头结尾锁定,但是这一题明确要求必须使用两次空格(个人觉得这里有点小bug,或者说有点歧义,毕竟利用分组来重复空格得到的结果也把重复的数字分开了),最终可以这样通过测试/^(\d+)\s\1\s\1$/
为了方便记忆,我把上述规则归纳到了下表中
以下是这部分习题的解答:
Introduction to the Regular Expression Challenges
-
1
2
3let myString = "Hello, World!";
let myRegex = /Hello/;
let result = myRegex.test(myString); // Change this line -
1
2
3let waldoIsHiding = "Somewhere Waldo is hiding in this text.";
let waldoRegex = /Waldo/; // Change this line
let result = waldoRegex.test(waldoIsHiding); Match a Literal String with Different Possibilities
1
2
3let petString = "James has a pet cat.";
let petRegex = /dog|cat|bird|fish/; // Change this line
let result = petRegex.test(petString);-
1
2
3let myString = "freeCodeCamp";
let fccRegex = /freeCodeCamp/i; // Change this line
let result = fccRegex.test(myString); -
1
2
3let extractStr = "Extract the word 'coding' from this string.";
let codingRegex = /coding/; // Change this line
let result = extractStr.match(codingRegex); // Change this line Find More Than the First Match
1
2
3let twinkleStar = "Twinkle, twinkle, little star";
let starRegex = /twinkle/gi; // Change this line
let result = twinkleStar.match(starRegex); // Change this lineMatch Anything with Wildcard Period
1
2
3let exampleStr = "Let's have fun with regular expressions!";
let unRegex = /.un/; // Change this line
let result = unRegex.test(exampleStr);Match Single Character with Multiple Possibilities
1
2
3let quoteSample = "Beware of bugs in the above code; I have only proved it correct, not tried it.";
let vowelRegex = /[aeiou]/gi; // Change this line
let result = quoteSample.match(vowelRegex); // Change this line-
1
2
3let quoteSample = "The quick brown fox jumps over the lazy dog.";
let alphabetRegex = /[a-z]/gi; // Change this line
let result = quoteSample.match(alphabetRegex); // Change this line Match Numbers and Letters of the Alphabet
1
2
3let quoteSample = "Blueberry 3.141592653s are delicious.";
let myRegex = /[h-s2-6]/gi; // Change this line
let result = quoteSample.match(myRegex); // Change this lineMatch Single Characters Not Specified
1
2
3let quoteSample = "3 blind mice.";
let myRegex = /[^aeiou0-9]/gi; // Change this line
let result = quoteSample.match(myRegex); // Change this lineMatch Characters that Occur One or More Times
1
2
3let difficultSpelling = "Mississippi";
let myRegex = /s+/g; // Change this line
let result = difficultSpelling.match(myRegex);Match Characters that Occur Zero or More Times
1
2
3let chewieQuote = "Aaaaaaaaaaaaaaaarrrgh!";
let chewieRegex = /Aa*/; // Change this line
let result = chewieQuote.match(chewieRegex);Find Characters with Lazy Matching
1
2
3let text = "<h1>Winter is coming</h1>";
let myRegex = /<h.*?1>/; // Change this line
let result = text.match(myRegex);Find One or More Criminals in a Hunt
1
2
3
4
5
6let crowd = 'P1P2P3P4P5P6CCCP7P8P9';
let reCriminals = /C+/g; // Change this line
let matchedCriminals = crowd.match(reCriminals);
console.log(matchedCriminals);Match Beginning String Patterns
1
2
3let rickyAndCal = "Cal and Ricky both like racing.";
let calRegex = /^Cal/; // Change this line
let result = calRegex.test(rickyAndCal);-
1
2
3let caboose = "The last car on a train is the caboose";
let lastRegex = /caboose$/; // Change this line
let result = lastRegex.test(caboose); -
1
2
3let quoteSample = "The five boxing wizards jump quickly.";
let alphabetRegexV2 = /\w/gi; // Change this line
let result = quoteSample.match(alphabetRegexV2).length; Match Everything But Letters and Numbers
1
2
3let quoteSample = "The five boxing wizards jump quickly.";
let nonAlphabetRegex = /\W/gi; // Change this line
let result = quoteSample.match(nonAlphabetRegex).length;-
1
2
3let numString = "Your sandwich will be $5.00";
let numRegex = /\d/g; // Change this line
let result = numString.match(numRegex).length; -
1
2
3let numString = "Your sandwich will be $5.00";
let noNumRegex = /\D/gi; // Change this line
let result = numString.match(noNumRegex).length; -
1
2
3let username = "JackOfAllTrades";
let userCheck = /[A-Za-z]+[A-Za-z]+\d*$/; // Change this line
let result = userCheck.test(username); -
1
2
3let sample = "Whitespace is important in separating words";
let countWhiteSpace = /\s/g; // Change this line
let result = sample.match(countWhiteSpace); Match Non-Whitespace Characters
1
2
3let sample = "Whitespace is important in separating words";
let countNonWhiteSpace = /\S/g; // Change this line
let result = sample.match(countNonWhiteSpace);Specify Upper and Lower Number of Matches
1
2
3let ohStr = "Ohhh no";
let ohRegex = /[^h]h{3,6}[^h]/; // Change this line
let result = ohRegex.test(ohStr);Specify Only the Lower Number of Matches
1
2
3let haStr = "Hazzzzah";
let haRegex = /Haz{4,}ah/; // Change this line
let result = haRegex.test(haStr);Specify Exact Number of Matches
1
2
3let timStr = "Timmmmber";
let timRegex = /Tim{4}ber/; // Change this line
let result = timRegex.test(timStr);-
1
2
3let favWord = "favorite";
let favRegex = /favou?rite/; // Change this line
let result = favRegex.test(favWord); Positive and Negative Lookahead
1
2
3let sampleWord = "astronaut";
let pwRegex = /(?=\w{5,})(?=\D*\d{2,})/; // Change this line
let result = pwRegex.test(sampleWord);Reuse Patterns Using Capture Groups
1
2
3let repeatNum = "42 42 42";
let reRegex = /^(\d+)\s\1\s\1$/; // Change this line
let result = reRegex.test(repeatNum);Use Capture Groups to Search and Replace
1
2
3
4let huhText = "This sandwich is good.";
let fixRegex = /good/; // Change this line
let replaceText = "okey-dokey"; // Change this line
let result = huhText.replace(fixRegex, replaceText);Remove Whitespace from Start and End
1
2
3let hello = " Hello, World! ";
let wsRegex = /\S+\s?\S+/; // Change this line
let result = hello.match(wsRegex)[0]; // Change this line