版权说明:本文档由用户提供并上传,收益归属内容提供方,若内容存在侵权,请进行举报或认领
文档简介
第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');//=true
reg.test('a');//=false
reg.test('a');//=true
reg.test('a');//=false
reg.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行看到了fntest()方法
pub(crate)fntest(
this:JsValue,
args:[JsValue],
context:mutContext,
)-JsResultJsValue{
//1.LetRbethethisvalue.
//2.IfType(R)isnotObject,throwaTypeErrorexception.
letthis=this.as_object().ok_or_else(||{
context
.construct_type_error("RegEtotype.testmethodcalledonincompatiblevalue")
});
//3.LetstringbeToString(S).
letarg_str=args
.get(0)
.cloned()
.unwrap_or_default()
.to_string(context);
//4.LetmatchbeRegExpExec(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,
)-JsResultOptionJsObject{
//1.Assert:Type(R)isObject.
//2.Assert:Type(S)isString.
//3.LetexecbeGet(R,"exec").
letexec=this.get("exec",context);
//4.IfIsCallable(exec)istrue,then
ifletSome(exec)=exec.as_callable(){
//a.LetresultbeCall(exec,R,«S»).
letresult=exec.call(this.clone().into(),[o()],context);
//b.IfType(result)isneitherObjectnorNull,throwaTypeErrorexception.
if!result.is_object()!result.is_null(){
returncontext.throw_type_error("regexpexecreturnedneitherobjectnornull");
//c.Returnresult.
returnOk(result.as_object().cloned());
//5.PerformRequireInternalSlot(R,[[RegExpMatcher]]).
if!this.is_regexp(){
returncontext.throw_type_error("RegExpExeccalledwithinvalidvalue");
//6.ReturnRegExpBuiltinExec(R,S).
Self::abstract_builtin_exec(this,input,context)
}
又在Self::abstract_exec()方法中找到了Self::abstract_builtin_exec()方法
pub(crate)fnabstract_builtin_exec(
this:JsObject,
input:JsString,
context:mutContext,
)-JsResultOptionJsObject{
//1.Assert:RisaninitializedRegExpinstance.
letrx={
letobj=this.borrow();
ifletSome(rx)=obj.as_regexp(){
rx.clone()
}else{
returncontext.throw_type_error("RegExpBuiltinExeccalledwithinvalidvalue");
//2.Assert:Type(S)isString.
//3.LetlengthbethenumberofcodeunitsinS.
letlength=input.encode_utf16().count();
//4.LetlastIndexbeℝ(ToLength(Get(R,"lastIndex"))).
letmutlast_index=this.get("lastIndex",context).to_length(context);
//5.LetflagsbeR.[[OriginalFlags]].
letflags=rx.original_flags;
//6.Ifflagscontains"g",letglobalbetrue;elseletglobalbefalse.
letglobal=flags.contains('g');
//7.Ifflagscontains"y",letstickybetrue;elseletstickybefalse.
letsticky=flags.contains('y');
//8.Ifglobalisfalseandstickyisfalse,setlastIndexto0.
if!global!sticky{
last_index=0;
//9.LetmatcherbeR.[[RegExpMatcher]].
letmatcher=rx.matcher;
//10.Ifflagscontains"u",letfullUnicodebetrue;elseletfullUnicodebefalse.
letunicode=flags.contains('u');
//11.LetmatchSucceededbefalse.
温馨提示
- 1. 本站所有资源如无特殊说明,都需要本地电脑安装OFFICE2007和PDF阅读器。图纸软件为CAD,CAXA,PROE,UG,SolidWorks等.压缩文件请下载最新的WinRAR软件解压。
- 2. 本站的文档不包含任何第三方提供的附件图纸等,如果需要附件,请联系上传者。文件的所有权益归上传用户所有。
- 3. 本站RAR压缩包中若带图纸,网页内容里面会有图纸预览,若没有图纸预览就没有图纸。
- 4. 未经权益所有人同意不得将文件中的内容挪作商业或盈利用途。
- 5. 人人文库网仅提供信息存储空间,仅对用户上传内容的表现方式做保护处理,对用户上传分享的文档内容本身不做任何修改或编辑,并不能对任何下载内容负责。
- 6. 下载文件中如有侵权或不适当内容,请与我们联系,我们立即纠正。
- 7. 本站不保证下载资源的准确性、安全性和完整性, 同时也不承担用户因使用这些下载资源对自己和他人造成任何形式的伤害或损失。
最新文档
- 热力管网工程档案管理规范
- 实验室工程监理实施细则
- 旅居康养服务项目投资估算报告
- 流域畜禽养殖污染治理实施方案
- 认知症照护中心建设与运营方案
- 社区公共卫生服务设施配置方案
- 小学课间活动优化实施方案
- 施工用电巡检培训
- 孕产妇围产期健康管理工作手册
- 有毒液体储罐风险评估报告
- 国家保安员资格考试培训教材
- 全国行业职业技能竞赛-全国乡村建设工匠(水电安装工)技能竞赛理论题库(附答案)
- 浴池办卫生许可管理制度
- 教育培训机构预付费制度
- 2025年中职电气技术应用(直流电路分析)试题及答案
- 北京市朝阳区2025-2026学年高三上学期期中质量检测数学试卷(解析版)
- 营地营运方案
- 仓库6S管理制度仓库现场6S执行标准仓库6S检查表
- 高校教研室年度工作总结范文
- 牧业财务管理办法
- T/JSSES 39-2024水体中抗生素环境风险评估技术指南
评论
0/150
提交评论