正则表达式分解剖析(一文悟透正则表达式)

1,257 阅读3分钟

看JavaScript框架设计,读到一段“innerHTML”操作无法执行里面的script标签里的代码,于是想动手弥补下该操作。 实现很简单,执行完innerHTML后,找出所有的script标签并取出里面的代码字符调用eval(),(仅考虑内联script标签),所以问题就来到了如何查找代码字符的问题上。这是正则表达式做的事.

本人比较懒惰,又不聪慧,就事论事,不求甚解,不求记忆,于是东西看了多遍,也记不住。我不打算改这个毛病, 因为我坚信优胜劣汰,有趣的东西才会被记忆存储,无趣的自然被遗忘淘汰。写这篇文章,是为了以后再找资料时的快速抵达目的地,节省time.

从字符说起

声明:暂不谈es6里的unicode字符扩展部分。

JavaScript里的字符:

  • 一种可以打印
  • 一种是无法打印的

能打印的熟知的有abcdefg,123456,数字也是字符?是的,难道数字无法打印?字符对应着某一个字符码点值(charCode), charCode范围从0到一个很大的数值(4位16进制:0000-ffff)

可以通过字符的 String.fromCharCode(index) 查看字符码点对应的字符

'a'.charCodeAt() //97
String.fromCharCode(97) // 'a'

不可打印字符一样对应着某个码点,所以任何字符都是在计算机系统中设计好了的,不是随意的。

var a = 123;
\u0061 //123
//16进制0061 对应着码点为97的a字符
//a字符被声明为了变量,打印出赋予的值,为123

不是所有的字符都能作为变量,但所有的字符都能组成字符串。 字符串绝对是计算机世界里的一等公民 ,因为,没有字符就没有一切,代码都是字符编写的。 处理字符串自然也是一项很重要的任务,具体可能是:字符的替换、增删、提取等 由于字符很多,超过一万个,开发者就需要一套套的模式来定义任务类型: 开头字符的特征,结尾字符的特征,中间字符的特征,不能包含某些字符... 这就是正则表达式的雏形,不同语言的正则可能略有不同,不过解决的问题源头都是一致的,因此使用方法也基本类似。

常用模式或场景

==以 x 、y、z代表某一字符==

  • 某字符开头、结尾:/^x//x$/
  • 某些可能的字符组成集合,也可以中划线指定字符范围:[xyza-z]
  • 不包含某些字符的集合:反向字符集合:[^xyz]
  • 字符多次出现:
    • 贪婪模式:/x?//x*//x+//x{n}//x{n,}//x{m,n}/
    • 非贪婪模式匹配:/+?/ ==仅匹配时==
    var reg = /^\d+?$/;
    reg.test(12313131);//返回true,因为是符合的
    var reg2 = /\d+?/;
    reg2.exec(12345);//匹配'1',因为非贪婪
    
  • 子表达式:/(abc)/捕获组并记忆,(?:abc)不捕获不记忆
  • 几个字符(子表达式)中的一个:/x|y|z/
  • 某个字符后跟特定字符 正向查找/x(?=y)/x后跟y,==y不是匹配内容==
  • 某个字符后不能跟特定字符 反向查找 /x(?!y)/

常用的方法

  • 验证字符串是否符合某一模式:test
  • 提取所有匹配项:match (==g标志==)
  • 捕获某些子串并记忆,用于插值
  • 检索某一个模式匹配到的索引:execsearch

画一张思维导图

在这里插入图片描述

实现前言中的小需求

function getScriptsFromString(string){
	let regexp = /<script[^>]*>([^<\/]*)<\/script>/g;
	let matches = [];
	let codes = [];
	let current = null
	while(current = regexp.exec(string)){
		matches.push(current[0]);
		codes.push(current[1]);
	}
	return {
		matches,
		codes 
	}
}
var string = `

<script >

alert(123123);

</script>
<script type="script" > 
console.log('inner script')
function getName(obj){
return obj.name
}
console.log(getName({name:'hezebing'}))
</script>

`
let result = getScriptsFromString(string);
result.codes.forEach(item => {
	eval(item);
})

全文完,欢迎有志之士留言或讨论,望不吝赐教!