注:最后有面试挑战,看看自己掌握了吗
🌸I could be bounded in a nutshell and count myself a king of infinite space.
特别鸣谢:木芯工作室 、Ivan from Russia
限制可能的用户名
用户名在互联网上随处可见。 它们是用户在自己喜欢的网站上的唯一身份。
需要检索数据库中的所有用户名。 以下是用户在创建用户名时必须遵守的一些简单规则。
用户名只能是数字字母字符。
用户名中的数字必须在最后。 数字可以有零个或多个。 用户名不能以数字开头。
用户名字母可以是小写字母和大写字母。
用户名长度必须至少为两个字符。 两位用户名只能使用字母。
修改正则表达式 userCheck 以满足上面列出的约束。
let username = "JackOfAllTrades"; let userCheck = /^[a-z][a-z]+\d*$|^[a-z]\d\d+$/i; // 修改这一行 let result = userCheck.test(username);
匹配空白字符
迄今为止的挑战包括匹配字母和数字。 还可以匹配字符之间的空格。
可以使用 \s 搜寻空格,其中 s 是小写。 此匹配模式将匹配空格、回车符、制表符、换页符和换行符
。 可以认为这类似于元字符 [ \r\t\f\n\v]
。
let whiteSpace = "Whitespace. Whitespace everywhere!" let spaceRegex = /\s/g; whiteSpace.match(spaceRegex);
这个 match 调用将返回 [" ", " "]
。
修改正则表达式 countWhiteSpace 查找字符串中的多个空白字符。
let sample = "Whitespace is important in separating words"; let countWhiteSpace = /\s/g; // 修改这一行 let result = sample.match(countWhiteSpace);
匹配非空白字符
已经学会了如何使用带有小写 s 的缩写 \s 来搜寻空白字符。 还可以搜寻除了空格之外的所有内容。
使用 \S 搜寻非空白字符
,其中 s 是大写。 此匹配模式将不匹配空格、回车符、制表符、换页符和换行符。 可以认为这类似于元字符 [^ \r\t\f\n\v]
。
let whiteSpace = "Whitespace. Whitespace everywhere!" let nonSpaceRegex = /\S/g; whiteSpace.match(nonSpaceRegex).length;
返回值的 .length 应该是 32。
修改正则表达式 countNonWhiteSpace 以查找字符串中的多个非空字符。
指定匹配的上限和下限
回想一下,使用加号 + 查找一个或多个字符,使用星号 * 查找零个或多个字符
。 这些都很方便,但有时需要匹配一定范围的
匹配模式。
可以使用数量说明符(quantity specifiers)指定匹配模式的上下限。 数量说明符与花括号({ 和 })一起使用
。 可以在花括号之间放两个数字,这两个数字代表匹配模式的上限和下限。
例如,要匹配出现 3 到 5 次字母 a 的在字符串 ah,正则表达式应为/a{3,5}h/。
let A4 = "aaaah"; let A2 = "aah"; let multipleA = /a{3,5}h/; multipleA.test(A4); multipleA.test(A2);
第一次 test 调用将返回 true,而第二次调用将返回 false。
修改正则表达式 ohRegex 以匹配出现 3 到 6 次字母 h 的字符串 Oh no。
只指定匹配的下限
可以使用带有花括号的数量说明符来指定匹配模式的上下限。 但有时候只想指定匹配模式的下限而不需要指定上限。
为此,在第一个数字后面跟一个逗号即可。
例如,要匹配至少出现 3 次字母 a 的字符串 hah,正则表达式应该是 /ha{3,}h/
。
let A4 = "haaaah"; let A2 = "haah"; let A100 = "h" + "a".repeat(100) + "h"; let multipleA = /ha{3,}h/; multipleA.test(A4); multipleA.test(A2); multipleA.test(A100);
按顺序排列,三次 test 调用将返回值 true,false 和 true。
指定匹配的确切数量
可以使用带有花括号的数量说明符来指定匹配模式的上下限。 但有时只需要特定数量的匹配。
要指定一定数量的匹配模式,只需在大括号之间放置一个数字。
例如,要只匹配字母 a 出现 3 次的单词hah,正则表达式应为/ha{3}h/。
let A4 = "haaaah"; let A3 = "haaah"; let A100 = "h" + "a".repeat(100) + "h"; let multipleHA = /ha{3}h/; multipleHA.test(A4); multipleHA.test(A3); multipleHA.test(A100);
按顺序排列,三次 test 调用将返回值 false,true 和 false。
修改正则表达式timRegex,以匹配仅有四个字母 m 的单词 Timber。
检查全部或无
有时,想要搜寻的匹配模式可能有不确定是否存在的部分。 尽管如此,还是想检查它们。
为此,可以使用问号 ? 指定可能存在的元素。 这将检查前面的零个或一个元素。 可以将此符号视为前面的元素是可选的。
例如,美式英语和英式英语略有不同,可以使用问号来匹配两种拼写。
let american = "color"; let british = "colour"; let rainbowRegex= /colou?r/; rainbowRegex.test(american); rainbowRegex.test(british);
上面的 test 都会返回 true。
修改正则表达式 favRegex 以匹配美式英语(favorite)和英式英语(favourite)的单词版本。
let favWord = "favorite"; let favRegex = /favou?rite/; // 修改这一行 let result = favRegex.test(favWord);
正向先行断言和负向先行断言
先行断言
(Lookaheads)是告诉 JavaScript 在字符串中向前查找的匹配模式。 当想要在同一个字符串上搜寻多个匹配模式时
,这可能非常有用。
有两种先行断言:正向先行断言(positive lookahead)和负向先行断言(negative lookahead)
。
正向先行断言会查看并确保搜索匹配模式中的元素存在
,但实际上并不匹配
。 正向先行断言的用法是 (?=…),其中 … 就是需要存在但不会被匹配的部分。
另一方面,负向先行断言会查看并确保搜索匹配模式中的元素不存在。 负向先行断言的用法是 (?!..),其中 … 是希望不存在的匹配模式。 如果负向先行断言部分不存在,将返回匹配模式的其余部分。
尽管先行断言有点儿令人困惑,但是这些示例会有所帮助。
let quit = "qu"; let noquit = "qt"; let quRegex= /q(?=u)/; let qRegex = /q(?!u)/; quit.match(quRegex); noquit.match(qRegex);
这两次 match 调用都将返回 ["q"]
。
先行断言的更实际用途是检查一个字符串中的两个或更多匹配模式。 这里有一个简单的密码检查器,密码规则是 3 到 6 个字符且至少包含一个数字:
let password = "abc123"; let checkPass = /(?=\w{3,6})(?=\D*\d)/; checkPass.test(password);
在正则表达式 pwRegex 中使用先行断言以匹配大于 5 个字符且有两个连续数字的密码。
let sampleWord = "astronaut"; let pwRegex = /(?=\w{5,})(?=\D+\d{2,})/; // 修改这一行 let result = pwRegex.test(sampleWord);
检查混合字符组
有时候我们想使用正则表达式里的括号 () 来检查字符组。
如果想在字符串找到 Penguin 或 Pumpkin,可以用这个正则表达式:/P(engu|umpk)in/g。
然后使用 test() 方法检查 test 字符串里面是否包含字符组。
let testStr = "Pumpkin"; let testRegex = /P(engu|umpk)in/; testRegex.test(testStr);
test 方法会返回 true。
完善正则表达式,使其以区分大小写的方式检查 Franklin Roosevelt 或 Eleanor Roosevelt 的名字,并且应该忽略 middle names。
然后完善代码,使创建的正则检查 myString,根据正则是否匹配返回 true 或 false
let myString = "Eleanor Roosevelt"; let myRegex = /(Franklin|Eleanor) (([A-Z]\.?|[A-Z][a-z]+) )?Roosevelt/; let result = myRegex.test(myString);
使用捕获组重用模式
当你想要匹配一个像下面这样多次出现的单词,
let repeatStr = "row row row your boat";
你可以使用 /row row row/。但如果你不知道重复的特定单词,怎么办? 捕获组 可以用于找到重复的子字符串。
捕获组是通过把要捕获的正则表达式放在括号中来构建的。 在这个例子里, 目标是捕获一个包含字母数字字符的词,所以捕获组是将 \w+ 放在括号中
:/(\w+)
/。
分组匹配的子字符串被保存到一个临时的“变量”, 可以使用同一正则表达式和反斜线及捕获组的编号来访问它(例如:\1)
。 捕获组按其开头括号的位置自动编号(从左到右),从 1 开始
。
下面的示例是匹配被空格隔开的两个相同单词:
let repeatRegex = /(\w+) \1 \1/; repeatRegex.test(repeatStr); // Returns true repeatStr.match(repeatRegex); // Returns ["row row row", "row"]
在字符串上调用 .match() 方法将返回一个数组,其中包含它最终匹配到的子字符串及其捕获组。
在 reRegex 中使用捕获组来匹配一个只由相同的数字重复三次组成的由空格分隔字符串。
let repeatNum = "42 42 42"; let reRegex = /^(\d+) \1 \1$/g; // 修改这一行 let result = reRegex.test(repeatNum);
使用捕获组搜索和替换
搜索功能是很有用的。 但是,当搜索同时也执行更改(或替换)匹配文本的操作时,
搜索功能就会显得更加强大。
可以在字符串上使用 .replace() 方法来
搜索并替换字符串中的文本。 .replace() 的输入首先是想要搜索的正则表达式匹配模式。 第二个参数是用于替换匹配的字符串或用于执行某些操作的函数
。
let wrongText = "The sky is silver."; let silverRegex = /silver/; wrongText.replace(silverRegex, "blue");
replace 调用将返回字符串 The sky is blue.。
你还可以使用美元符号($)访问替换字符串中的捕获组
。
"Code Camp".replace(/(\w+)\s(\w+)/, '$2 $1');
调用 replace 将返回字符串 Camp Code
。
使用三个捕获组编写一个正则表达式 fixRegex,这三个捕获组将搜索字符串 one two three 中的每个单词。 然后更新 replaceText 变量,以字符串 three two one 替换 one two three,并将结果分配给 result 变量。 确保使用美元符号($)语法在替换字符串中使用捕获组。
let str = "one two three"; let fixRegex = /^(\w+)\s(\w+)\s(\w+)$/g; // 修改这一行 let replaceText = "$3 $2 $1"; // 修改这一行 let result = str.replace(fixRegex, replaceText);
删除开头和结尾的空白
有时字符串周围存在的空白字符并不是必需的。 字符串的典型处理是删除字符串开头和结尾处的空格。
编写一个正则表达式并使用适当的字符串方法删除字符串开头和结尾的空格。
注意: String.prototype.trim() 方法在这里也可以实现同样的效果
,但是你需要使用正则表达式来完成此项挑战。
let hello = " Hello, World! "; let wsRegex = /^(\s+)|(\s+)$/g; // 修改这一行 let result = hello.replace(wsRegex,""); // 修改这一行