关键词: 正则 校验 字符串
本文所作的主要目的是为了要用到正则的时候,能尽快解决问题,对正则有个大致概念。
所以开篇内容类似《飞行手册》以案例和工具为主。
好用的正则工具
常用的正则
//Email地址 /^\w+([-+.]\w+)*@\w+([-.]\w+)*\.\w+([-.]\w+)*$/g //手机号码 /^1[3-9]\d{9}$/g //固定电话 /^(\(\d{3,4}-)|\d{3.4}-)?\d{7,8}$/ //身份证号码(15位、18位数字) /^\d{15}|\d{18}$/ //中国邮政编码(中国邮政编码为6位数字) /[1-9]\d{5}(?!\d)/ //URL /^(((ht|f)tps?):\/\/)?([^!@#$%^&*?.\s-]([^!@#$%^&*?.\s]{0,63}[^!@#$%^&*?.\s])?\.)+[a-z]{2,6}\/?/ //匹配HTML标签 /<(\w+)[^>]*>(.*?<\/\1>)?/ //html注释 /<!--[\s\S]*?-->/g // 取闭合标签 match /(<span class="blue">)([\S\s]*?)(\<\/span>)/g // 替换标签 replace(/\<i\>(.*?)\<\/i\>/g,"<span>$1</span>") //img src /<img [^>]*src=['"]([^'"]+)[^>]*>/ //金额校验,精确到2位小数 /^[0-9]+(.[0-9]{2})?$/ // 1000->1,000 金额格式化 replace(/\B(?=(\d{3})+(?!\d))/g,',') //输入数字或者小数 /^\d*\.?\d*$/g
概念定义
正则表达式本质是文本处理工具,是由普通字符和特殊字符组成的文字模板。
正则规则
匹配字符
字符 | 说明 |
. | 匹配除换行符以外的任意字符 |
\ | 转义符 |
\d | 匹配数字, 等价于字符组[0-9] |
\D | 匹配非数字的任意字符, 等价于[^0-9] |
\w | 匹配字母, 数字, 下划线 |
\W | 匹配除字母,数字,下划线之外的任意字符 |
\s | 匹配任意的空白符(包括制表符,空格,换行等) |
\S | 匹配非空白的任意字符 |
[...] | 字符组 |
[^...] | 排除性字符组 |
{min,max} | 量词,至少出现 min 次,最多出现 max 次 |
{min} | 量词,出现 min 次 |
? | 量词,出现0次或者1次,等价于{0,1} |
+ | 量词,至少出现1次,等价于{1,} |
* | 量词,出现一次,等价于{0,} |
'abc abbc abbbc abbbbc abbbbbc abbbbbbc'.match(/ab{2,5}c/g) // ['abbc', 'abbbc', 'abbbbc', 'abbbbbc'] 'a0b a1b a2b a3b a4b'.match(/a[0-3]b/g) // ['a0b', 'a1b', 'a2b', 'a3b']
贪婪 & 非贪婪
正则本身是贪婪的,默认会尽可能的多匹配符合模式的字符。
可以量词后面加一个?
,就变成非贪婪。让正则表达式尽可能少的匹配,一旦成功就不再继续尝试。
贪婪量词 | 非贪婪量词 |
{m,n} | {m,n}? |
{m,} | {m,}? |
? | ?? |
+ | +? |
* | *? |
const str = '123 1234 12345 123456' // 贪婪 str.match(/\d{2,5}/g) // 非贪婪 str.match(/\d{2,5}?/g) // ['123', '1234', '12345', '12345'] // ['12', '12', '34', '12', '34', '12', '34', '56'] const nstr = "123456789" nstr.replace(/\d{3,6}/,'换成这个') nstr.replace(/\d{3,6}?/,'换成这个') // 替换成这个789 // 替换成这个456789
多选分支
按照分支的顺序逐个匹配,当前面的分支满足要求了,则舍弃后面的分支。
ab|cd
=> 匹配'ab'或者'cd'字符子串。
'good idea, nice try.'.match(/good|nice/g) // ['good', 'nice']
应用题
- 匹配id
- 匹配16进制的颜色值
- 匹配24小时制时间
- 匹配日期
匹配位置
字符 | 说明 |
\b | 单词的边界,匹配单词开始或结束的位置 |
\B | 非单词边界。例如在字符串中所有位置中,扣掉\b,剩下的都是\B 的。 |
^abc$ | 字符串开始、结束的位置 |
(?=p) | 正向先行断言。符合p(子模式)前面的那个位置。 |
(?!p) | 负向先行断言。(?=p)取反的意思 |
(?<=p) | 符合p(子模式)后面的那个位置。 |
(?<!p) | (?<=p)取反 |
// 单词边界 '[[show_me_code.html]]'.replace(/\b/g, '| ') // 非单词边界 '[[show_me_code.html]]'.replace(/\B/g, '| ') // '[[| show_me_code| .| html| ]]' // '| [| [s| h| o| w| _| m| e| _| c| o| d| e.h| t| m| l]| ]| ' // 正向先行断言 在符合条件的地方前面 'show_me_code'.replace(/(?=show)/g, '| ') // 负向先行断言 在符合条件的地方以外 'show_me_code'.replace(/(?!show)/g, '| ') // '| show_me_code' // s| h| o| w| _| m| e| _| c| o| d| e| // 符合p(子模式)后面的位置 'show_me_code'.replace(/(?<=show)/g, '| ') // (?<=p)匹配到的位置之外的位置 'show_me_code'.replace(/(?<!show)/g, '| ') // 'show| _me_code' // '| s| h| o| w_| m| e| _| c| o| d| e| '
应用题
- 数字的千分位分割法
- 手机号3-4-4分割
- 验证密码的合法性
分组
让量词作用于一个整体。分组中的分支结构则有点像 ||
// ab 是一个分组 'ababa abbb ababab'.match(/(ab)+/g) console.log(string) // ["abab", "ab", "ababab"] /I love (JavaScript|Regular Expression)/.test('I love JavaScript') // true /I love (JavaScript|Regular Expression)/.test('I love Regular Expression') // true
分组引用
常用来界定重复限定符的范围, 以及将字符分组. 如: (ab)+ 可以匹配abab..等, 其中 ab 便是一个分组。
// 提取年月日 const reg = /(\d{4})-(\d{2})-(\d{2})/ const str = '2023-03-06' reg.test(str) // 反向引用 console.log(RegExp.$1) // 2023 console.log(RegExp.$2) // 03 console.log(RegExp.$3) // 06 // 数据替换 // 2023-03-06 -> 03/06/2023 '2023-03-06'.replace(/(\d{4})-(\d{2})-(\d{2})/, '$2/$3/$1') '2023-03-06'.replace(/(\d{4})-(\d{2})-(\d{2})/, () => { return RegExp.$2 + '/' + RegExp.$3 + '/' + RegExp.$1 }) '2023-03-06'.replace(/(\d{4})-(\d{2})-(\d{2})/, ($0, $1, $2, $3) => { return $2 + '/' + $3 + '/' + $1 })
非捕获性括号
非捕获性分组, 匹配正则的位置, 但不捕获匹配结果。
也就是说不创建反向引用, 就好像没有括号一样.
"#808080".replace(/#(?:\d+)/,"$1"+"~~") // $1~~ console.log(RegExp.$1); // "" "#808080".replace(/#(\d+)/,"$1"+"~~") // 808080~~ console.log(RegExp.$1); // "808080"
应用题
- trim 方法模拟
- 将每个单词的首字母大写 my name is => My Name Is
- 驼峰化 -moz-transform => MozTransform
- 中划线化 MozTransform => -moz-transform
- HTML转义和反转义
- 匹配成对的标签