常用字符
正则中很多需要强记的字符,这里列出常用的字符和其表达的含义:
匹配特殊字符本身时需要转义,共有以下几个:
* . ? + $ ^ [ ] ( ) { } | /
- 其中 / 在字面量中需要转义,在构造函数中不需要,如下匹配一个斜杠 /。
const reg = ///const reg = new RegExp('/')
- 在字面量中带一个转义符 的用构造函数写要带两个转义符 ,如下匹配一个字符串 . 。
const reg = /./const reg = new RegExp('.')
常用方法
js 中的正则表达式分为字面量和构造函数两种:
// 字面量const reg = /[0-9a-z]/g// 构造函数const reg = new RegExp('[0-9a-z]', 'g')
其中字面量中不能包含变量,构造函数中可以使用变量:
const name = '幻灵尔依'const reg = new RegExp(`我的名字叫${name}`)
经常会用 reg.test(str) 方法来判断字符串中是否匹配到了正则表达式:
const reg = /[0-9]/const str = '文本中有没有数字1234等'if (reg.test(str)) { ...}
也经常用str.replace(reg, '') 方法来替换字符串中的内容:
const reg = /[0-9]/gconst str = '文本中的数字1234全部替换成x'const newStr = str.replace(reg, 'x')
也会用到 str.match(reg) 方法来获取匹配到的内容(也可以用reg.exec(str)):
const reg = /[0-9]+[.][0-9]+[.][0-9]+/gconst str = '这里有个表名字叫做 11.11.11'str.match(reg) // ['11.11.11']
- match 中的正则表达式如果使用g标志,则将返回与完整正则表达式匹配的所有结果,但不会返回捕获组。
- 如果未使用g标志,则仅返回第一个完整匹配及其相关的捕获组(Array)。 在这种情况下,返回的项目将具有如下所述的其他属性。
老子曰:下面才是精华
贪婪&非贪婪
* 和 + 限定符都是贪婪的,它们会尽可能多的匹配文字。在它们的后面加上一个 ? 就可以实现非贪婪或最小匹配。
- 贪婪(默认都是贪婪的)
const str = '
正则表达式
'const reg = /<.>/str.match(reg) // ['
正则表达式
']
- 非贪婪
const str = '
正则表达式
'const reg = /<.>/str.match(reg) // ['
']
捕获分组和回溯引用
小括号 () 匹配到的子表达式会被缓存为一个个组,方便后面对其引用。假设要获取html中的 h1 标签:
- 在正则表达式中使用 可以引用第n个捕获组
const str = '
正则表达式
正则表达式
正则表达式
'const reg = /.+?1>/str.match(reg) // ['
正则表达式
']
- 在正则表达式外使用 $n 引用第n个捕获组(RegExp.$n)
const str = 'abc'const reg = /(abc)/RegExp.$1 // 'abc'str.replace(reg, '$1$1') // 'abcabc'
非捕获分组和限定查找
因为捕获组 () 会将每个捕获到的结果缓存下来以便引用,所以会造成内存使用增加。如果只是想用分组的原始功能,而不需要缓存,则可以使用非捕获分组 (?:)
const str = 'abc'const reg = /(?:abc)/RegExp.$1 // ''
非捕获分组还有 (?=)、(?<=)、(?!)、(?
前向查找
前向查找是用来限制后缀的。
- (?=): 即查找符合限定条件 (?=) 的前面的匹配项(输出内容不包括 (?=) 中的匹配项)
const str = 'a.png b.jpg c.gif d.svg'// 查找所有 边界开头的、 .svg 前面的 小写字母。const reg = /b[a-z](?=.svg)/gstr.match(reg) // ['d']
- (?!): 即查找 不符合 限定条件 (?!) 的前面的匹配项(输出内容不包括 (?!) 中的匹配项)
const str = 'a.png b.jpg c.gif d.svg'// 查找所有边界开头的、 非.svg 前面的、 `.[a-z]{3}` 前面的 小写字母。const reg = /b[a-z](?!.svg)(?=.[a-z]{3})/gstr.match(reg) // ['a', 'b', 'c']
后向查找
后向查找是用来限制前缀的。
- 查找符合限定条件 (?<=) 的后面的匹配项(输出内容不包括 (?<=) 中的匹配项)
const str = '1. 1111; 2. 2222; 3. 3333; 4. 4444。'// 查找所有 序号 后面的项。const reg = /(?<=b[0-9]+.s).+?[;。]/gstr.match(reg) // ["1111;", "2222;", "3333;", "4444。"]
- 查找 不符合 限定条件 (?
const str = 'a.png b.jpg c.gif d.svg'// 查找前缀不为 a b c 的后面的项const reg = /b(?
来个能吃的栗子
一般稍微复杂的正则都是多种规则同时使用的,下面来几个例子吧:
前向查找和后向查找齐用:
假设要获取
中的 data-img-url 属性中的链接。可以确定的是链接左边一定是 data-img-url=" ,右边一定是紧贴着 " (非贪婪)。
const str = ''const dataImgUrl = 'data-img-url'const reg = new RegExp(`(?<=${dataImgUrl}=").+?(?=")`, 'g')str.match(reg) // ['https://test.com']
回溯引用和非贪婪并用
假如我要获取一段html中的文本,但是我又不想要加了 not-show-in-text 标记的标签中的文本,可以这样:
const notShowInText = 'not-show-in-text'const html = `
test1
表 1.4.4 测试表格
test2
`const reg = new RegExp(`]+${notShowInText}[sS]+?1>`, 'g')const text = html.replace(reg, '').replace(/]+>/g, '')
其中最关键的是要匹配到 not-show-in-text 所在的整个标签。([a-z][a-z1-6]*?) 匹配了一个非贪婪的标签名,[^>] 保证了 < 到 > 是一个半个完整的标签,1> 匹配一个闭合的标签, [sS]+? 匹配了标签见可能出现的任意元素且是非贪婪的。
replace第二个参数可以是回调函数
比如,想把 yyyy-mm-dd 格式,替换成 mm/dd/yyyy 怎么做?
var regex = /(d{4})-(d{2})-(d{2})/;var string = "2017-06-12";var result = string.replace(regex, "$2/$3/$1");console.log(result); // "06/12/2017"
其中 replace 第二个参数里用$1、$2、$3指代相应的分组。等价于如下的形式:
var regex = /(d{4})-(d{2})-(d{2})/;var string = "2017-06-12";var result = string.replace(regex, function() {return RegExp.$2 + "/" + RegExp.$3 + "/" + RegExp.$1;});console.log(result); // "06/12/2017"
也等价于:
var regex = /(d{4})-(d{2})-(d{2})/;var string = "2017-06-12";var result = string.replace(regex, function(match, year, month, day) {return month + "/" + day + "/" + year;});console.log(result); // "06/12/2017"
作者:幻灵尔依