正则表达式精通测验
你能驯服那些狂野的正则表达式吗?
准备好和正则表达式搏斗一番了吗?🤼♂️
用涵盖基本模式、量词、分组以及那些棘手的环视断言的问题,来测试你的正则知识。从简单的字符串匹配到复杂的模式验证——你能找出正确的正则表达式吗?
匹配什么?
'cat CAT Cat'.match(/cat/g)这个模式使用了 g,但没有使用 i:
g查找所有匹配- 没有
i标志时,匹配是区分大小写的
没有 i 标志,只有小写的 “cat” 会匹配。
这在处理用户输入或 HTML 时特别有用,因为大小写可能不同。
这段代码会返回什么?
const words = ['cat', 'hat', 'what', 'bat'];words.filter(word => word.match(/^[ch]at/))模式 /^[ch]at/ 匹配的字符串需满足:
- 以
^开头,且第一个字符是 ‘c’ 或 ‘h’([ch]表示一个字符类,匹配一个字符) - 后面紧跟字面量 ‘at’
因此,只有 “cat” 和 “hat” 符合该模式。filter() 方法会保留所有匹配的元素。
这个模式会匹配到什么?
'<div>Hello</div><div>World</div>'.match(/<div>.*?<\/div>/g)模式 /<div>.*?<\/div>/g 使用了非贪婪匹配,*? 表示:
- 匹配
<div> - 匹配任意字符(
.*),但尽可能少(?) - 直到找到
</div> g标志使其匹配所有出现
如果没有 ?,贪婪的 .* 会从第一个 <div> 匹配到最后一个 </div>,得到一个大的匹配。加上 ? 后,它会分别匹配每一对。
这将返回什么?
'hello\nworld'.match(/\w+/g)\w+ 模式匹配一个或多个单词字符。尽管字符串中有换行符,\w 匹配:
- 字母 (a-z, A-Z)
- 数字 (0-9)
- 下划线 (_)
因此,换行符充当了单词边界,我们得到两个匹配。如果我们使用 .*,默认情况下它不会匹配换行符(你需要 s 标志才能匹配)。
这个模式会匹配到什么?
'$100 and €50'.match(/\d+(?=[\$€])/g)这个模式不会匹配任何内容,因为先行断言用反了!如果你想要匹配前面有 $ 或 € 的数字,请使用后行断言:/(?<=[\$€])\d+/g。
先行断言检查的是当前位置之后的内容。这个模式写的是:
- 一个或多个数字(
\d+) - 后面跟着(
(?=...))$或€([\$€])
由于没有数字后面跟着货币符号(它们前面才有货币符号),所以没有匹配。
什么会匹配?
'cat cats category'.match(/\bcat\b/g)\b 表示单词边界,它匹配:
- 单词字符与非单词字符之间的位置
- 字符串开头/结尾(如果该位置是单词字符)
因此 /\bcat\b/ 仅在 “cat” 是一个完整的单词时匹配它,而不是作为另一个单词的一部分。
- ✅ “cat”(前后有空格)
- ❌ “cats”(“cat” 后面没有边界)
- ❌ “category”(“cat” 后面没有边界)
输出是什么?
'banana'.match(/a/g)g(全局)标志改变了 match() 的行为:
- 没有
g:返回第一个匹配项及其捕获组 - 有
g:返回所有匹配字符串的数组
在这个例子中,它找到 “banana” 中所有 “a” 的出现。
注意:如果你需要同时获取所有匹配项和捕获组,请使用 matchAll() 或循环中的 exec() 方法。
这将返回什么?
'2029-12-31'.match(/(\d{4})-(\d{2})-(\d{2})/).slice(1)该模式使用了三个捕获组:
(\d{4})捕获年份(\d{2})捕获月份(\d{2})捕获日期
不带 g 标志的 match() 返回:
- 索引 0:完整匹配
- 索引 1+:捕获组
slice(1) 是获取仅捕获组的常用技巧。
以下代码的结果是什么?
"123aBc".match(/^\d+(?![a-z])/ig)负向前瞻 (?![a-z]) 确保数字后面没有小写字母。由于 “3aBc” 部分在数字后面有一个小写字母,所以该部分不匹配。因此只有开头的 “12” 匹配。
返回什么?
'a,b,c'.split(/(?<=,)/)模式 /(?<=,)/ 是一个后顾断言,匹配逗号之后的位置:
a,(逗号之后)b,(逗号之后)c(后面没有逗号)
后顾断言不会消耗逗号,因此逗号仍然附着在分割结果的前一个片段上。
当你想要根据前面的内容分割字符串,同时保留分割字符时,这非常有用。
匹配什么?
'$100'.match(/$\d+/)特殊字符需要使用 \ 进行转义才能匹配字面量:
$是一个特殊字符(字符串结尾)- 要匹配字面量的美元符号,请转义它:
\$
需要转义的常见字符:
. * + ? ^ $ [ ] \ ( ) { } |如果不转义,许多特殊字符的正则表达式含义可能不是你想要的。
匹配了什么?
'$100'.match(/(?<=\$)\d+/)正向向后查找 (?<=\$) 确保数字前面有一个美元符号:
(?<=\$): 向后查找美元符号\d+: 匹配一个或多个数字
向后查找断言不会消耗字符,它们只检查前面的内容。 当你想要根据前面的内容匹配某些内容而不包括前面的部分时,这很有用。
匹配了什么?
'<b>bold</b>'.match(/<b>(.*?)<\/b>/).slice(1)该模式使用 *? 进行懒惰匹配:
<b>:匹配开始标签(.*?):捕获任意字符(懒惰)</b>:匹配结束标签
* 后面的 ? 使其变为懒惰模式,尽可能少地匹配字符。
如果没有 ?,它将是贪婪模式,尽可能多地匹配。
slice(1) 返回捕获组的内容。
匹配什么?
'😀 🙂'.match(/\p{Emoji}/gu)u 标志启用:
- Unicode 属性转义(
\p{...}) - 正确处理代理对
没有 u 标志,表情符号和其他 Unicode 字符可能无法正确匹配。
模式 \p{Emoji} 匹配具有 Unicode Emoji 属性的字符。在这个字符串中,这意味着两个表情符号图形。
注意:Unicode 属性转义需要 u 标志。
提前道歉!😈
哪个密码匹配这个模式?
/^(?=.*[A-Z])(?=.*[a-z])(?=.*\d)(?=.*[!@#$%^&*]).{8,}$/不要在生产中写这样的代码!😅
这个模式使用了多个正向先行断言来强制要求:
- 至少一个大写字母:
(?=.*[A-Z]) - 至少一个小写字母:
(?=.*[a-z]) - 至少一个数字:
(?=.*\d) - 至少一个特殊字符:
(?=.*[!@#$%^&*]) - 最小长度8个字符:
.{8,}
先行断言非常适合密码验证,因为它们可以在不消耗字符的情况下检查多个条件。
你答得怎么样?🧐
正则表达式可能是个难驯的猛兽,但一旦你掌握了它(以及所有的新语法),它就会变得无比强大。继续练习,你很快就会成为正则大师!🧙♂️
做完这些正则题想歇口气?
哼,记住:技能 之后 再休息!
去我的健身房再碾压几个挑战吧!💪