【javascript】常用正则分组捕获匹配

前言

  • 今天别人问了个正则问题把我问住了,匹配半天没匹配出来,最终到处找资料搞定了,因为js的正则匹配和其他语言有些区别,还有分组方面有些坑,特此记录下

js正则常用捕获符

  • 必须先弄懂这个,基础就不说了,里面还有些坑。
  • 小括号就是分组,分组里面有这样几种:
    (?=) positive lookahead 正向前瞻型捕获
    (?!) negative lookahead 负向前瞻型捕获
    (?<=) positive lookbehind 正向后顾型捕获
    (?<!) negative lookbehind 负向后顾型捕获
    (?:)非捕获分组
  • 只要使用上面的那几种模式,那么js返回给你的是不包括这个括号里的东西,这个有个特别大的好处,因为js使用正则分组有个坑,就是在全局匹配情况下分组,最后使用RegExp.$1只能出来最后一个匹配的分组,不能把所有匹配到的第一个分组拿出来。我百度了半天没发现全局拿所有分组的办法,如果有人知道怎么做可以留言给我。我百度到最好的解决方法除了这个就是利用lastIndex自己写循环匹配。
  • 于是因为js正则有这个捕获问题,所以上面的模式就变得特别常用。特别是在对全局匹配的情况下。

起组名

  • 一般情况下都是不需要起名,用默认的$1,$2。python里面起名用?P<xxx>,js里起名用?<xxx>,js引用分组使用\k<组名>,默认分组使用\数字

常用符号

  • \w 匹配字母或数字或下划线或汉字。与([0-9a-zA-Z_])等价。

  • \s 匹配任意的空白符

  • \d 匹配数字

  • \b 匹配单词的开始或结束

  • 点(.)表示匹配出换行符以外的任意一个字符串

  • 星号(*)表示匹配前面一个字符串0次或多次

常见匹配需求

一、匹配对象前后有固定字符串

  • 我们拉取了后台数据,是个嵌套好多层的json,但是我就想要所有元素的一个字段,并且提取出来,不使用循环,如果用循环太墨迹了,因为有好几层嵌套。比如:
{"departmentId":1,
"departmentName":"zzz",
	"child":[{"departmentId":2,
				"departmentName":"测试部门",
				"child":[{"departmentId":5,
						"departmentName":"试试"}
						]},
			{"departmentId":3,
			"departmentName":"威风威风",
			"child":[{"departmentId":6,"departmentName":"试试44"}]
			},
			{"departmentId":4,"departmentName":"测试部门2"}
	]
}
  • 需求:我们要把所有层级的departmentName拿出来
  • 思路:前面有个固定字符,后面固定是个引号,由于上面说的js分组无法取全局,所以借助捕获符直接提取目标。格式就是(?<=前面的字符串)(中间的内容)(?=后面的字符串)。这个分组就是前面说的前瞻后顾捕获。
let reg = /(?<="departmentName"\:")(.*?)(?=")/g
console.log(str.match(reg))

[ ‘zzzz’, ‘测试部门’, ‘试试’, ‘威风威风’, ‘试试44’, ‘测试部门2’ ]

  • 代码里中间.*?就是懒惰匹配,就是尽可能短的匹配到中间字符,否则用.*结果就会一直匹配到最后一个部门。

二、匹配页面元素

  • 很多时候,会提取页面标签正则判断。页面标签有个特点,就是会有个相同的闭合标签。
  • 比如:
let str =`"<html><h1>www.yehuozhili.cn</h1></html><html><h1>www.yehuozhili.cn</h1></html>"`
  • 我们想按html分成2组
let reg = /\<(\w*)\>.*?\<\/\1\>/g
console.log(str.match(reg))
//输出[
//  '<html><h1>www.yehuozhili.cn</h1></html>',
//  '<html><h1>www.yehuozhili.cn</h1></html>'
//]
  • 其中\w表示任意英文,加个*表示多个,这个\1就表示默认的第一个分组了,就是第一个标签里提取的英文,这样可以保证左边是什么标签右边闭合是什么标签。
  • 如果想匹配h1标签呢?我们把\w*换成h1即可。
let reg2 = /\<(\h1)\>.*?\<\/\1\>/g
console.log(str.match(reg2))
//输出 [ '<h1>www.yehuozhili.cn</h1>', '<h1>www.yehuozhili.cn</h1>' ]
  • 那么我想要标签里内容怎么做?如果是非全局匹配,那比较简单,如果全局匹配,就有点复杂。
  • 我们可以放弃原有的标签分组,直接写死,然后利用分组捕获提取。
let reg2 = /(?<=\<\h1\>).*?(?=\<\/h1\>)/g
console.log(str.match(reg2))
//输出  [ 'www.yehuozhili.cn', 'www.yehuozhili.cn' ]

三、路由匹配

  • 路由匹配有个特点,比如/user ,如果是精准匹配,那么/user/或者/user都是可以通的。但是/user/xxx是不能通的,/usersxxsd也不能通
  • 思路:前面没啥说的,主要是后面,可能有/,如果有/后面不能有东西,如果没/必须精准匹配字。所以使用括号分组但不包括,这个组可能有,可能没有就是问号,最终都是直接结束,所以$。如果有/,那么里面必须结尾没东西,用前瞻捕获来看。
let str =`/user`
let reg = /^\/user(?:\/(?=$))?$/g
console.log(str.match(reg))
  • 这里介绍个生成路由的正则库path-to-regexp,使用它就可以生成路由正则,和上面那个一样。
let pathToRegexp=require('path-to-regexp')
let regexp = pathToRegexp('/user',[],{end:true});
console.log(regexp)
  • 再介绍个正则查看网站。可以很清楚看见正则效果是什么样的。我实验了下,好像不支持js设置分组名。?P的python设置分组名也认不得。
发布了163 篇原创文章 · 获赞 9 · 访问量 3万+

猜你喜欢

转载自blog.csdn.net/yehuozhili/article/details/103730033
今日推荐