JavaScript正则表达式中g标志实例分析
本篇内容主要讲解“JavaScript正则表达式中g标志实例分析”,感兴趣的朋友不妨来看看。本文介绍的方法操作简单快捷,实用性强。下面就让小编来带大家学习“JavaScript正则表达式中g标志实例分析”吧!
有一天在思否社区看到有个问题,大致描述如下
constlist=['a','b','-','c','d'];constreg=/[a-z]/g;constletters=list.filter(i=>reg.test(i));//letters===['a','c'];//如果正则不使用`g`标志可以得到所有的字母//为什么加入`g`之后就不可以了
对问题而言,遍历中的i就是一个字符,不需要用到g。
但是就我对正则的理解(过于浅薄)感觉上有没有g(只是全局搜索,不会匹配到就停下来)应该不影响,激发了我的好奇心。
上面题的建议写法如下
constreg=/[a-z]/g;reg.test('a');//=>truereg.test('a');//=>falsereg.test('a');//=>truereg.test('a');//=>falsereg.test('a');//=>true
解密过程
首先可以确定的表现一定是g导致的
搜索引擎
打开 MDN 仔细查看g标志的作用,得到结论和我的理解无二。
我猜想应该就是g可能启用了某种缓存,又因为reg相对过滤器是全局变量,我将代码改为:
constlist=['a','b','-','c','d'];constletters=list.filter(i=>/[a-z]/g.test(i));//letters===['a','b','c','d'];
将正则声明到每一次遍历,得到结论就是正确的,验证了我的猜想。也得到了,缓存就是正则中的某个地方
下面我找到对应的源码来查看问题的原因
源码层面
由于最近在看 Rust,所以使用 Rust 编写的源码查看
打开项目后,点击.进入 vscode 模式,command+p 搜索 regexp 关键词
进入test.rs文件,command+f 搜索/g
可以找到在 90 行有个last_index()
的测试
#[test]fnlast_index(){letmutcontext=Context::default();letinit=r#"varregex=/[0-9]+(\.[0-9]+)?/g;"#;//forward的作用:更改context,并返回结果的字符串。eprintln!("{}",forward(&mutcontext,init));assert_eq!(forward(&mutcontext,"regex.lastIndex"),"0");assert_eq!(forward(&mutcontext,"regex.test('1.0foo')"),"true");assert_eq!(forward(&mutcontext,"regex.lastIndex"),"3");assert_eq!(forward(&mutcontext,"regex.test('1.0foo')"),"false");assert_eq!(forward(&mutcontext,"regex.lastIndex"),"0");}
看到了有lastIndex关键字,这里再已经大致猜到问题的原因了,g 标志存在匹配后的最后一个下标,导致出现问题。
我们将视线移入到mod.rs文件中,搜索test
在 631 行看到了fn test()方法
pub(crate)fntest(this:&JsValue,args:&[JsValue],context:&mutContext,)->JsResult{//1.LetRbethethisvalue.//2.IfType(R)isnotObject,throwaTypeErrorexception.letthis=this.as_object().ok_or_else(||{context.construct_type_error("RegExp.prototype.testmethodcalledonincompatiblevalue")})?;//3.Letstringbe?ToString(S).letarg_str=args.get(0).cloned().unwrap_or_default().to_string(context)?;//4.Letmatchbe?RegExpExec(R,string).letm=Self::abstract_exec(this,arg_str,context)?;//5.Ifmatchisnotnull,returntrue;elsereturnfalse.ifm.is_some(){Ok(JsValue::new(true))}else{Ok(JsValue::new(false))}}
在test()
方法中找到了Self::abstract_exec()
方法
pub(crate)fnabstract_exec(this:&JsObject,input:JsString,context:&mutContext,)->JsResult
又在Self::abstract_exec()
方法中找到了Self::abstract_builtin_exec()
方法
pub(crate)fnabstract_builtin_exec(this:&JsObject,input:&JsString,context:&mutContext,)->JsResult
Self::abstract_builtin_exec()
方法中存在global以及last_index这样看来最终执行的方法就是在这里了,仔细查看该方法中的代码(代码写的很详细而且每一步都有注释)
在第 12 步中:
lastIndex 超过文本长度且当 global 存在时将 lastIndex 置为 0
获取匹配到的值(match_value
)
如果未匹配到则置为advance_string_index()
方法的返回值
advance_string_index()
不在当前问题的考虑范围https://tc39.es/ecma262/#sec-...
第 13 步获取匹配到的值的 endIndex
第 15 步将 lastIndex 置为 endIndex
至此也就整明白了g
标志的含义,在正则的原型链中存在一个lastIndex
,如果匹配为真时lastIndex
不会重置为 0 ,下一次开始时继承了上次位置,
结论
在问题代码中分析
constreg=/[a-z]/g;//声明后,lastIndex为0reg.test('a');//=>true;第一次匹配后,lastIndex为1reg.test('a');//=>false;第二次匹配由于lastIndex为1,且字符只有一个,得到false,将lastIndex置为0reg.test('a');//=>true;下面依次循环前两次的逻辑reg.test('a');//=>false;reg.test('a');//=>true;
到此,相信大家对“JavaScript正则表达式中g标志实例分析”有了更深的了解,不妨来实际操作一番吧!这里是恰卡编程网网站,更多相关内容可以进入相关频道进行查询,关注我们,继续学习!