# 字符匹配对应的练习题
正则类的问题可以拆解成固定的套路:纵向模糊匹配 + 横向模糊匹配。
对应到具体知识点就是:元字符、字符组、量词、分支结构。
# 一、16 进制颜色值
给定字符串(以下字符串中不一定都是正确的十六进制)
#ffbbad #f1234 #Fc01DF #FFF #ffE
要求匹配正确的十六进制颜色值。
分析:
1.起始字符是#
2.十六进制的字符范围是 0-9, a-f, A-F
根据纵向模糊匹配,可以使用字符组: [0-9a-fA-F]
3.字符只能是 3 位或者 6 位
根据横向模糊匹配,可以使用量词和分支结构
🍬
var regex = /(#[0-9a-fA-F]{6})|((#[0-9a-fA-F]{3})\s)|(#[0-9a-fA-F]{3}$)/g;
var string = "#ffbbad #f1234 #Fc01DF #FFF #ffE";
console.log( string.match(regex) );
// => ["#ffbbad", "#Fc01DF", "#FFF ", "#ffE"]
勘误
书中给出的正则表达式是 /#([0-9a-fA-F]{6}|[0-9a-fA-F]{3})/g,这个是不够准确的,因为当字符串中含有不正确的十六进制时,就会匹配到意外的情况。
比如 #f1234 ,因为只有5位,所以这是个错误的十六进制颜色值,但是用书中的正则表达式会匹配出来 #f12, 这是不符合期望的。
为什么会匹配出来 #f12?
答:因为分支结构是惰性的,所以优先匹配出现6次的字符[0-9a-fA-F]{6},#f1234 中除了 # 只有5个字符,所以不满足规则,继续匹配出现3次的字符[0-9a-fA-F]{3},#f1234 中具有满足此规则的字符串#f12,所以就匹配到了。
优化
我的正则中使用了 \s 和 $ 这两个元字符:
(#[0-9a-fA-F]{3})\s在后面加上\s的作用就是,确保3位的16进制颜色值后面必须是一个空格,这样就能避免把4位或者5位,截断成3位。(#[0-9a-fA-F]{3})$在后面加上$的作用就是,确保3位的16进制颜色值后面是字符串的结尾,避免遗漏最后一个匹配结果。
# 二、匹配时间
以 24 小时制为例。
要求匹配:
23:59
02:07
分析:
1.数字的范围是0-9
2.第一位只能是0、1、2
3.第二位依赖于第一位的选择:
- [0][0-9]
- [1][0-9]
- [2][0-3]
汇总为 [01][0-9]|[2][0-3]
4.第三位[0-5] 5.第四位[0-9]
🍬
var regex = /^([01][0-9]|[2][0-3]):[0-5][0-9]$/;
console.log( regex.test("23:59") );
console.log( regex.test("02:07") );
// => true
// => true
如果也要求匹配 "7:9", 也就是说时分前面的 "0" 可以忽略。
🍬
var regex = /^([2][0-3]|1[0-9]|0?[0-9]):([1-5][0-9]|0?[0-9])$/;
console.log( regex.test("23:59") );
console.log( regex.test("02:07") );
console.log( regex.test("7:9") );
// => true
// => true
// => true
# 三、匹配日期
以 yyyy-mm-dd 格式为例。
要求匹配:
2017-06-10
分析: 1.年 [0-9]{4} 但实际上 1970 之前的年份用的场景比较少,这里就只考虑 1970 以及之后的年份。
[1][9][7-9][0-9]|[2-9][0-9]{3}
2.月:01-12 [0][1-9]|[1][0-2]
3.天:每个月的天数是不一样的
[0][1-9]|[12][0-9]|[3][01]
这个其实还是不够准确的,因为每个月天数不一样,后续会补充一个更完整的。
🍬
var regex = /^[0-9]{4}-(0[1-9]|1[0-2])-(0[1-9]|[12][0-9]|3[01])$/;
console.log( regex.test("2017-06-10") );
// => true
# 四、匹配id
要求从
<div id="container" class="main"></div>
提取出 id="container"
分析:
1.整体可以看成是id="x",其中只有 x 是变量,所以进一步分析 x
2.id 的值
- id 的值不得包含空白字符(whitespace,包括空格和制表符等)
- 使用除 ASCII 字母、数字、_、- 和 . 以外的字符可能会造成兼容性问题,因为 HTML 4 中不允许使用它们。虽然这个限制在 HTML5 中被解除了,但为兼容性考虑 ID 应该以字母开头。
通过上述描述可以发现,x 推荐的值是 ASCII 字母、数字、_、- 和 .组合而成的
🍬
var regex = /id="([-_a-zA-Z0-9\.])*"/
var string = '<div id="container" class="main"></div>';
console.log(string.match(regex)[0]);
// => id="container"
但是一般id 的值可以用 . 来匹配,因为可以默认id的值是正确的。
注意:* 是贪婪匹配,. 可以匹配到 ",所以会把 class 也匹配进来,只要变成惰性模式就行了
🍬
var regex = /id=".*?"/
var string = '<div id="container" class="main"></div>';
console.log(string.match(regex)[0]);
// => id="container"
另外一种方法,使用脱字符^,把 " 排除
🍬
var regex = /id="[^"]*"/
var string = '<div id="container" class="main"></div>';
console.log(string.match(regex)[0]);
// => id="container"