正则表达式全局查找多个子项的情景

使用正则表达式如何全局查找多个子项呢?

最近群里有个同学提出了个问题,"kjdkfjdkkdjf_xkdfjkdhttp://www.xxx.com/news/th/123.htmlxxxxxkjdfdk" 一个正则怎么把 123 拿出来,123 可以是任何内容即可,有群友给出了个非常精简的 match 解决方案。

代码如下:

'dkfdf/a.html, dkfjkdjf/b.html'.match(/([^\/.]+)(?=\.html)/g) // 666
// => ["a", "b"]

正则表达式 – (?!), (?:), (?=) 使用方式可参考:https://www.cnblogs.com/allen2333/p/9835654.html

当然还有另外的群友给出了用 exec 的方案,参考引用:https://nosaid.com/article/regex-in-javascript#exec,代码如下:

const content = `
<script data-key="key1" src="1.js"></script>
<script data-key="key2" src="2.js"></script>
<script data-key="key3" src="3.js"></script>
`;

const reg = /data-key="(\S+?)"\s*src="(\S+?)"/g;

let m;
let matches = [];

while ((m = reg.exec(content))) {
    matches.push(m);
}

console.log(matches);

// output:
// [
//     ['data-key="key1" src="1.js"', 'key1', '1.js'],
//     ['data-key="key2" src="2.js"', 'key2', '2.js'],
//     ['data-key="key3" src="3.js"', 'key3', '3.js']
// ]

难度升级,如果是要把特征改为,必须是 news/th/123.html 即以 news/th/ 开头呢?
可以使用 (?<=pattern) 非获取匹配,反向肯定预查,代码如下:

'www.xxx.com/news/th/a.html, www.yyy.com/news/th/b.html'.match(/(?<=news/th/)([^\/.]+)(?=\.html)/g)
// => ["a", "b"]

【正则表达式】前瞻,后顾,负前瞻,负后顾

举个例子:

有个字符串

str = "博客园 顾客 博客 客园"

我们想匹配字符串里"博客园"的"客"字而不要其他的"客"字,这时就需要用到前瞻后顾。

正则表达式如下:

(?<=博)客(?=园)

反过来,我们不想要"博客园"的"客"字,但是想要其他"客"字。这时就要用到负前瞻,负后顾

正则表达式如下:

(?<!博)客(?!园)

总结一下:

前瞻: exp1(?=exp2) 查找 exp2 前面的 exp1

后顾: (?<=exp2)exp1 查找 exp2 后面的 exp1

负前瞻: exp1(?=exp2) 查找后面不是 exp2 的 exp1

负后顾: (?<=exp2)exp1 查找前面不是 exp2 的 exp1

可以发现,负前瞻、负后顾就是把前瞻、后顾中的"="改成了"!"

注意:后顾功能在大多数语言中有长度限制,只能使用定长的表达式,像 \w+\d 这样的表达式长度可变,不能用在后顾中

一个复杂一点的例子:

str = "data: '|12 34 56 78 90|', data: '|12|3456|7890|', data: '|12|', data: '1234567890', data: '|1234|' "

我们要匹配 data 后面有 || 的部分,要求里面没有空格没有 | 并且长度大于 2

(?<=data: ')\|[^ \|]{2,}?\|(?=')
可以匹配到 |1234|